次のようなマクロリストに情報が保存されています。
#define MYLIST(XX) \
XX(1, hello) \
XX(2, world) \
...
ここで、このマクロを同じ「呼び出しスタック」で2回使用したいと思います。これはばかげた例です:
#define BB(i,n) i +
#define AA(i,n) i + (MYLIST(BB) 0) +
int foo = MYLIST(AA) 0;
ただし、2回目MYLIST
は拡張されないため、これは機能しません。
int foo = 1 + (MYLIST(BB) 0) + 2 + (MYLIST(BB) 0) + 0;
MYLIST
既存のリストを使用して、同じ「コールスタック」で2回使用する方法(または回避策)はありますか?
次のコードが機能します。
#define EVAL(...) __VA_ARGS__
#define EVAL2(...) EVAL(__VA_ARGS__)
#define EMPTY()
#define DELAYED_CALL(F, ...) F EMPTY()(__VA_ARGS__)
#define BB(i,n) i +
#define AA(i,n) i + (MYLIST(BB) 0) +
#define MYLIST(XX) \
DELAYED_CALL(XX, 1, hello) \
DELAYED_CALL(XX, 2, world)
int foo = EVAL2(MYLIST(AA)) 0;
出力: int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
残念ながら、これが機能する理由を深く理解していません。このような場合に役立つ傾向があるいくつかのトリックを試しました。しかし、私はそれのいくつかを説明することができます。
マクロに「これ以上展開しない」というフラグが立てられることがあります。フラグは通常、展開を開始すると設定され、展開が終了すると設定が解除されます。これは再帰を防ぐ傾向があります。
マクロが通常は関数のようなマクロ呼び出しであるトークンに展開されるとき、それらが展開されるフェーズをすでに通過している場合があります。
評価時に2番目のマクロを追加してマクロ呼び出しを作成することにより、フラグが問題を引き起こさないポイントまでマクロの展開を遅らせることで、最初の問題を回避できます。それが何をするかDELAYED_CALL
です。しかし、そうすることで、2番目の問題EVAL
が発生するため、マクロを再スキャンするためにいくつかの呼び出しを追加する必要があります(関数のようなマクロへの引数は常にスキャンされるため、トークンのシーケンスを関数に渡します-引数をエコーするだけのマクロのように、再スキャンが発生します)。
すべてを機能させるために、2、3回の再スキャンが必要になる場合があります。EVAL2(X)
の省略形ですEVAL(EVAL(X))
。より多くの評価が必要になる場合があります。
以下のコードは、何が起こっているのかを少し明確にします。MYLIST2バージョンに必要なEVALが1つ少ないことに注意してください。これは、AAがMYLISTを呼び出し、MYLIST2が問題のフラグが設定されているためです。
#define EVAL(...) __VA_ARGS__
#define EVAL2(...) EVAL(__VA_ARGS__)
#define EVAL3(...) EVAL2(__VA_ARGS__)
#define EMPTY()
#define DELAYED_CALL(F, ...) F EMPTY()(__VA_ARGS__)
#define BB(i,n) i +
#define AA(i,n) i + (MYLIST(BB) 0) +
#define MYLIST(XX) \
DELAYED_CALL(XX, 1, hello) \
DELAYED_CALL(XX, 2, world)
#define MYLIST2(XX) \
XX(1, hello) \
XX(2, world)
% MYLIST
int foo = MYLIST(AA) 0;
int foo = EVAL(MYLIST(AA)) 0;
int foo = EVAL2(MYLIST(AA)) 0;
% MYLIST2
int foo = MYLIST2(AA) 0;
int foo = EVAL(MYLIST2(AA)) 0;
int foo = EVAL2(MYLIST2(AA)) 0;
これの出力は次のようになります。
% MYLIST
int foo = AA (1, hello) AA (2, world) 0;
int foo = 1 + (BB (1, hello) BB (2, world) 0) + 2 + (BB (1, hello) BB (2, world) 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
% MYLIST2
int foo = 1 + (BB (1, hello) BB (2, world) 0) + 2 + (BB (1, hello) BB (2, world) 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
(%記号は特別なものではありません。出力に表示されるコメントが必要で、前処理中にCスタイルのコメントが削除されます。)
さらに読む。記事の著者は、これを私よりもはるかによく理解しています。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加