私は最近同様の問題に遭遇しましたが、解決策があると信じています。
NUM_ARGS
重要なアイデアは、可変引数マクロに与えられた引数の数をカウントするマクロを作成する方法があるということです。NUM_ARGS
buildのバリエーションを使用できますNUM_ARGS_CEILING2
。これにより、可変個引数マクロに 1 つの引数が与えられているか、2 つ以上の引数が与えられているかがわかります。次に、2 つのヘルパー マクロのうちの 1 つにその引数を送信するようにBar
マクロを作成できます。NUM_ARGS_CEILING2
CONCAT
このトリックを使用してマクロを作成する例を次に示します。UNIMPLEMENTED
これは、に非常によく似ていBAR
ます。
ステップ1:
/**
* A variadic macro which counts the number of arguments which it is
* passed. Or, more precisely, it counts the number of commas which it is
* passed, plus one.
*
* Danger: It can't count higher than 20. If it's given 0 arguments, then it
* will evaluate to 1, rather than to 0.
*/
#define NUM_ARGS(...) \
NUM_ARGS_COUNTER(__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, \
12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define NUM_ARGS_COUNTER(a1, a2, a3, a4, a5, a6, a7, \
a8, a9, a10, a11, a12, a13, \
a14, a15, a16, a17, a18, a19, a20, \
N, ...) \
N
ステップ 1.5:
/*
* A variant of NUM_ARGS that evaluates to 1 if given 1 or 0 args, or
* evaluates to 2 if given more than 1 arg. Behavior is nasty and undefined if
* it's given more than 20 args.
*/
#define NUM_ARGS_CEIL2(...) \
NUM_ARGS_COUNTER(__VA_ARGS__, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 1)
ステップ2:
#define _UNIMPLEMENTED1(msg) \
log("My creator has forsaken me. %s:%s:%d." msg, __FILE__, \
__func__, __LINE__)
#define _UNIMPLEMENTED2(msg, ...) \
log("My creator has forsaken me. %s:%s:%d." msg, __FILE__, \
__func__, __LINE__, __VA_ARGS__)
ステップ 3:
#define UNIMPLEMENTED(...) \
CONCAT(_UNIMPLEMENTED, NUM_ARGS_CEIL2(__VA_ARGS__))(__VA_ARGS__)
CONCAT は通常の方法で実装されます。簡単なヒントとして、上記が紛らわしいと思われる場合: CONCAT の目的は、別のマクロ「呼び出し」に展開することです。
NUM_ARGS 自体は使用されないことに注意してください。ここで基本的なトリックを説明するためにそれを含めました。Jens Gustedt の P99 ブログを参照してください。
2 つの注意事項:
NUM_ARGS は、処理する引数の数が制限されています。数は完全に任意ですが、私の場合は最大 20 までしか処理できません。
示されているように、NUM_ARGS には、引数が 0 の場合に 1 を返すという落とし穴があります。その要点は、NUM_ARGS が技術的には [コンマ + 1] をカウントしていて、引数ではないということです。この特定のケースでは、実際に有利に機能します。_UNIMPLEMENTED1 は空のトークンを問題なく処理し、_UNIMPLEMENTED0 を書き込む必要がなくなります。Gustedt にも回避策がありますが、私はそれを使用したことがなく、ここで行っていることで機能するかどうかはわかりません。