31357


`print_test.hpp` のインクルード前に `#define` するかどうかで (例: `#define USEMYPRINT`)，  
`print_test.hpp` および `print_test.cpp` 内を，`#ifdef` ~ `#else` ~ `#endif`
により分岐させようとしています．

この際に `.cpp` ファイル内まで，`#define` で定義した内容が反映されませんでした．  
このため，実体が生成されず，LNK 2019 エラーが発生してしまいます．  
このような場合は，一般的にどのように解決されているでしょうか？

例えば，Eigen (線形代数演算ライブラリ) の場合，

[code]

    #define EIGEN_NO_DEBUG              // コード内のassertを無効化．
    //#define EIGEN_DONT_PARALLELIZE    // 並列を無効化．
    //#define EIGEN_MPL2_ONLY           // LGPLライセンスのコードを使わない．
    #include "Eigen/Dense"
    
[/code]

のように，インクルード前に `#define` することで，`assert` の無効化等を行うことができ，  
非常に便利だと感じました．(しかし，私には一見するだけでは，どのように実現しているかわから‌​ず……)

下記にかなり簡略化したサンプルを示します．(この場合，`.hpp` 内では，`#define USEMYPRINT` が認識されていますが，`.cpp`
内では，認識されず，実体が生成できないため，リンクエラーとなります)

よろしくお願いいたします．

環境 win8.1 Microsoft Visual Studio 2015 C++

main.cpp

[code]

    #include <stdio.h>
    
    #define USEMYPRINT // main.cpp 内でインクルード前に #define で定義されているかどうかにより，print_test.cpp および print_test.hpp で分岐を行いたい．
    #include "print_test.hpp"
    
    int main(){
        MyPrintf();
        return 0;
    }
    
[/code]

print_test.hpp

[code]

    #pragma onece
    #include <stdio.h>
    
    #ifdef USEMYPRINT
    void MyPrintf();
    #endif//USEMYPRINT
    
[/code]

print_test.cpp

[code]

    #include "print_test.hpp"
    
    #ifdef USEMYPRINT
    void MyPrintf(){
        printf("Hello my printf.\n");
    }
    #endif//USEMYPRINT
    
[/code]

* * *

(みなさま，ご回答どうもありがとうございます．問題を解決することができました．  
また，自分で見直しても質問の意図が分かり難かったため，可能な限り修正いたしました)

* * *

具体性が乏しいとご指摘をいただきましたので，修正したサンプルコードを下記に示します．(余り具体性が増していませんが，実体は下記のコードと同じ構成です)  
すみません．上記サンプルコードでは，実体を定義するかどうかとなっていますが，実際には，実体を定義するかしないかの制御 (sayuri
様のご回答により，出力されるバイナリに変化はないと分かったため，下記サンプルでは省略)，に加えて，文中で説明しているように，モードの切り替えも行いたい，と考えていました．

main.cpp

[code]

    #include <stdio.h>
    
    // Debug option
    #define MyClass_Mode2
    #include "MyClass.hpp"
    
    int main(){
        class MyClass* p_mc = new MyClass();
        p_mc->MyFunction();
        delete p_mc;
        return 0;
    }
    
[/code]

MyClass.hpp

[code]

    #pragma onece
    
    #include <stdio.h>
    
    class MyClass{
    private:
    public:
        MyClass();
        ~MyClass();
        void MyFunction();
    };
    
[/code]

MyClass.cpp

[code]

    #include "MyClass.hpp"
    
    void MyClass::MyFunction(){
    #ifndef MyClass_Mode2
        printf("Mode1.\n");
    #else
        printf("Mode2.\n");
    #endif
    }
    
[/code]


CC BY-SA 3.0
2016-12-24T18:40:40.513
31356
2016-12-31T06:10:31.937
2016-12-28T17:59:51.973
20009
20009
question
c++ c
ヘッダインクルード前の #define により，コンパイル内容を分岐・制御したい


一般的には、

[code]

    #define USEMYPRINT // main.cpp 内でインクルード前に #define で定義されているかどうかにより，print_test.cpp および print_test.hpp で分岐を行いたい．
    
[/code]

の様な定義は`プロジェクト名.hpp`等のファイルにまとめ、そのファイルを適宜インクルードするのが良いと思います。  
今回の例ですと、

プログラム名.hpp

[code]

    #define USEMYPRINT
    
[/code]

main.cpp

[code]

    #include "プログラム名.hpp"
    #include "print_test.hpp"
    
[/code]

print_test.hpp

[code]

    #pragma onece
    #include <stdio.h>
    #include "プログラム名.hpp"
    
    #ifdef USEMYPRINT
    void MyPrintf();
    #endif //USEMYPRINT
    
[/code]

print_test.cpp

[code]

    #include "プログラム名.hpp"
    #include "print_test.hpp"
    
    #ifdef USEMYPRINT
    void MyPrintf(){
        printf("Hello my printf.\n");
    }
    #endif //USEMYPRINT
    
[/code]

の様にして、.cppでの`#define`を避け、`#define`は必ずヘッダーファイルで行い、そのシンボルを参照するソースファイルは必ず`#define`をまとめたヘッダーファイルをインクルードするようにすると良いと思います。


CC BY-SA 3.0
2016-12-24T21:18:13.957
31357
2016-12-24T21:18:13.957
14745
31356
answer


質問の趣旨がいまいちよくわからないため見当はずれな回答かもしれませんが、

コンパイラーオプション [/Gy; 関数レベルのリンクの有効化](https://msdn.microsoft.com/ja-
jp/library/xsa71f43.aspx) およびリンカーオプション [/OPT:NOREF;
参照されない関数とデータの削除](https://msdn.microsoft.com/ja-jp/library/bxwfs976.aspx)
の機能があります。両機能を組み合わせることを前提にprint_test.cppファイル内で常に`MyPrintf()`を定義して構いませんし、print_test.hppファイル内で常に`MyPrintf()`を宣言して構いません。

main.cpp内で使用されなければ自動的に削除されます。

* * *

追記を受けて、やりようはいくらでもあると思います。  
先述したように使用されなかった関数は消されますから両方定義してしまい、ヘッダーファイル内で分岐してしまうとか。クラス定義内に書かれた関数は自動的にインラインとなるため、最適化されればオーバーヘッドもないはずです。  
これはあくまでテンプレート引数を嫌うコメントを受けての例です。

MyClass.hpp

[code]

    #pragma once
    
    #include <stdio.h>
    
    
    class MyClass {
    private:
        void MyFunction_Mode1();
        void MyFunction_Mode2();
    public:
        MyClass() = default;
        ~MyClass() = default;
        void MyFunction() {
    #ifndef MyClass_Mode2
            MyFunction_Mode1();
    #else
            MyFunction_Mode2();
    #endif
        }
    };
    
[/code]

MyClass.cpp

[code]

    #include "MyClass.hpp"
    
    #ifndef MyClass_Mode2
    #define MyFunction MyFunction_Mode1
    #else
    #define MyFunction MyFunction_Mode2
    #endif
    
    void MyClass::MyFunction() {
    #ifndef MyClass_Mode2
        printf("Mode1.\n");
    #else
        printf("Mode2.\n");
    #endif
    }
    
[/code]

MyClass_Mode2.cpp

[code]

    #define MyClass_Mode2
    #include "MyClass.cpp"
    
[/code]


CC BY-SA 3.0
2016-12-24T21:22:50.217
31358
2016-12-31T06:10:31.937
2016-12-31T06:10:31.937
4236
4236
31356
answer