プリプロセッサマクロに追加できますか?
-
13-10-2019 - |
質問
マクロ定義に材料を追加する標準CまたはGNU拡張機能では、何か方法はありますか? 例えば, 、asを定義したマクロを与えられます
#define List foo bar
追加できますか bas
それがそうです List
私がそれを定義したかのように拡張します
#define List foo bar bas
?
私はこのようなことができることを望んでいました:
#define List foo bar bas
#define List_ Expand(List)
#undef List
#define List Expand(List_) quux
しかし、私はそれを定義する方法を理解することはできません Expand()
マクロなので、私がやりたいことをします。
動機:私はこれらの線に沿って差別された/タグ付きの組合で遊んでいます:
struct quux_foo { int x; };
struct quux_bar { char *s; };
struct quux_bas { void *p; };
enum quux_type {quux_foo, quux_bar, quux_bas};
struct quux {
enum quux_type type;
union {
struct quux_foo foo;
struct quux_bar bar;
struct quux_bas bas;
} t;
};
これはX-Macroにとって良い場所だと思います。マクロを定義する場合
#define quux_table X(foo) X(bar) X(bas)
したがって、列挙と構造を定義することができ、同期から抜け出さないでください。
#define X(t) quux_ ## t,
enum quux_type {quux_table};
#undef X
#define X(t) struct quux_ ## t t;
struct quux {
enum quux_type type;
union {quux_table} t;
};
#undef X
もちろん、 quux_*
構造は同期しなくなる可能性があるので、私はこのようなことをしたいのですが、合法的にだけです。
struct quux_foo { int x; };
#define quux_table quux_table X(foo)
struct quux_bar { char *s; };
#define quux_table quux_table X(bar)
struct quux_bas { void *p; };
#define quux_table quux_table X(bas)
(まあ、何 本当 できるようになりたいのは次のことです
member_struct(quux, foo) { int x; };
しかし、私はマクロをマクロ内から(再)定義することはできないことをよく知っています。)
とにかく、それが私のやる気のある例です。これを達成する方法はありますか?
boost.preprocessorの例は問題ありません。x-macroテクニックをそのライブラリで動作させる方法を教えてください。
解決
事実上、いいえ。
マクロはゆっくりと評価されています。あなたがいつ #define List_ Expand(List)
, 、その交換リストは4つのトークンのシーケンスです Expand
, (
, List
, 、 と )
. 。マクロを交換リストに拡張する方法はありません。
マクロが呼び出されると、すべてのマクロ交換が行われます。
自動コード生成にBoost.Preprocessorライブラリを使用することをお勧めします。それは少し仕事ですが、あなたはいくつかを達成することができます かなり印象的なこと それを使用します。 Cと完全に互換性があるはずです。
他のヒント
やり方がある!
新しい_pragmaキーワードを使用して、これはGCCで達成できます(ただし、MSVCではありません)
独自の定義内にマクロをポップすると、マクロが初めて拡張されるまで拡張が遅れます。これにより、それ自体の定義の以前の拡張部分を作成できます。ただし、拡張中にポップされるため、1回しか使用できません
これが動作中にそれを見るためのいくつかのサンプルコードです
#define pushfoo _Pragma("push_macro(\"foo\")") //for convenience
#define popfoo _Pragma("pop_macro(\"foo\")")
#define foo 1
pushfoo //push the old value
#undef foo //so you don't get a warning on the next line
#define foo popfoo foo , 2 //append to the previous value of foo
pushfoo
#undef foo
#define foo popfoo foo , 3
pushfoo
#undef foo
#define foo popfoo foo , 4
foo //this whole list will expand to something like popfoo foo popfoo foo popfoo foo , 4
//which will in turn expand to 1 , 2 , 3 , 4
foo //the second time this will expand to just 1
このオプションは、GCCだけでのみ、自動コード生成をかなり簡単にする必要があります(多分Clang、テストしていないかもしれません)
正直に言うと、なぜこれが機能しなければならないのかを見つけることができる理由はありません。おそらく、おそらく未定義の行動が機能します。その理由は、Fooをポップした後、拡張されている現在のマクロがシンボルを許可するFooという名前に関連付けられなくなったことを推測しています。 foo
拡張するために、しかしそれは私の推測だけです
編集:
Clangでテストした後、これ ではない Clangで動作します。
Clangがうまくいかなかったと思った理由はわかりません。別のマシンではなかったのかもしれません。私は間違いなくそれを指定されたコードで動作させました
これが役立つかどうかはわかりませんが、Vari Argマクロを行うことができます。 X264プロジェクトのConrad氏は、前処理器の乱用が大好きです。彼らが彼らが助けてくれるかもしれないように聞こえるならあなたはもっと知ることができます ここ