web-dev-qa-db-ja.com

C ++マクロを再定義してから定義し直すことはできますか?

コードでJUCEライブラリといくつかのBoostヘッダーの両方を使用しています。 Juceは「T」をマクロ(うめき声)として定義し、Boostはテンプレート定義で「T」を使用することがよくあります。その結果、Boostヘッダーの前に何らかの方法でJUCEヘッダーを含めると、プリプロセッサがBoostコードのJUCEマクロを展開し、コンパイラが絶望的に​​失われます。

インクルードを正しい順序に保つことはほとんどの場合難しいことではありませんが、他のクラスを含むJUCEクラスがあり、チェーンのどこかにBoostが含まれている場合、およびその前のファイルがある場合は注意が必要です。あなたが困っていることを含むJUCEが必要でした。

これを修正するための私の最初の希望は

#undef T

boostのインクルードの前。しかし、問題は、それを再定義しないと、他のコードが「T」が宣言されていないことを混乱させることです。

それから私は多分私がそのようにいくつかの循環#defineトリックをすることができると思いました:

// some includes up here
#define ___T___ T
#undef T
// include boost headers here
#define T ___T___
#undef ___T___

醜いですが、うまくいくかもしれないと思いました。

残念ながら違います。 「T」をマクロとして使用している場所でエラーが発生する

'___T___' was not declared in this scope.

これら2つのライブラリを確実に連携させる方法はありますか?

40
Aftermathew

Greyfadeが指摘したように、プリプロセッサは非常に単純な生き物であるため、___T___トリックは機能しません。別のアプローチは、プラグマディレクティブを使用することです。

 // juice includes here
 #pragma Push_macro("T")
 #undef T
 // include boost headers here
 #pragma pop_macro("T")

これはMSVC++で機能するはずであり、GCCは互換性のためにpop_macroPush_macroのサポートを追加しました。技術的には実装に依存しますが、一時的に定義を抑制する標準的な方法はないと思います。

64
Peter

問題のあるライブラリを別のインクルードでラップし、#define Tを内部にトラップできますか?

例えば:

JUICE_wrapper.h:     
#include "juice.h"
#undef T

main.cpp:    
#include "JUICE_wrapper.h"    
#include "boost.h"

 rest of code....
11
Martin Beckett

それから私は多分私がそのようにいくつかの循環#defineトリックをすることができると思いました:

Cプリプロセッサはこのようには機能しません。プリプロセッサシンボルは、関数を定義するときにシンボルに意味が与えられるのと同じ意味で定義されていません

プリプロセッサをテキスト置換エンジンと考えると役立つ場合があります。シンボルが定義されると、ファイルの終わりまで、または未定義になるまで、まっすぐなテキスト置換として扱われます。その値はどこにも保存されないため、コピーできません。したがって、#undefを実行した後にTの定義を復元する唯一の方法は、コードの後半の新しい#defineでその値を完全に再現することです。

あなたができる最善のことは、単にBoostを使用しないか、JUCEの開発者にTをマクロとして使用しないように請願することです。 (または、最悪の場合、マクロの名前を変更して自分で修正してください。)

4
greyfade