10
#define PP_ARG0_(arg0, ...) arg0
#define PP_REST_(arg0, ...) __VA_ARGS__
#define PP_ARG0(args) PP_ARG0_ args
#define PP_REST(args) PP_REST_ args

#define FUNCTION(name) void name();
#define FUNCTION_TABLE(...)                   \
    FUNCTION(PP_ARG0((__VA_ARGS__)))          \
    FUNCTION_TABLE(PP_REST((__VA_ARGS__)))    \

テストコード:

FUNCTION_TABLE(f1, f2,f3,testA,testB,testC);

明らかに、再帰的な展開のため、宣言するだけvoid f1(); で、残りは展開されません。

void f1(); FUNCTION_TABLE(f2,f3,testA,testB,testC);

この場合、再帰的な展開を実現するにはどのようなトリックを使用できますか? 問題は、多くの引数 (最大 100) をサポートする必要があり、絶対にブーストを使用できないことです。

4

3 に答える 3

10

最も簡単な解決策は、次のようなシーケンス反復を使用することです。

#define CAT(x, y) PRIMITIVE_CAT(x, y)
#define PRIMITIVE_CAT(x, y) x ## y

#define FUNCTION(name) void name();
#define FUNCTION_TABLE(seq) CAT(FUNCTION_TABLE_1 seq, _END)
#define FUNCTION_TABLE_1(x) FUNCTION(x) FUNCTION_TABLE_2
#define FUNCTION_TABLE_2(x) FUNCTION(x) FUNCTION_TABLE_1
#define FUNCTION_TABLE_1_END
#define FUNCTION_TABLE_2_END

次にFUNCTION_TABLE、可変長引数の代わりにプリプロセッサ シーケンスを使用して呼び出します。

FUNCTION_TABLE((f1)(f2)(f3)(testA)(testB)(testC))

これははるかに単純であるだけでなく、再帰的なソリューションを使用するよりも高速です(つまり、コンパイルが高速です)(あなたが示したものや、こちらのようなものなど)。

于 2013-06-07T22:59:23.540 に答える
4

誰かが同じことをしたい場合の答えは次のとおりです。

#define _PP_0(_1, ...) _1            // (a,b,c,d) => a
#define _PP_X(_1, ...) (__VA_ARGS__) // (a,b,c,d) => (b,c,d)

//for each a in __VA_ARGS__ do f(a,x) 
//where x is some parameter passed to PP_TRANSFORM
#define PP_TRANSFORM(f,x,...) \
    PP_JOIN(PP_TRANSFORM_,PP_NARG(__VA_ARGS__))(f,x,(__VA_ARGS__))

#define PP_TRANSFORM_0(...)
#define PP_TRANSFORM_1( f,x,a) f(_PP_0 a,x) PP_TRANSFORM_0( f,x,_PP_X a)
#define PP_TRANSFORM_2( f,x,a) f(_PP_0 a,x) PP_TRANSFORM_1( f,x,_PP_X a)
...
#define PP_TRANSFORM_51(f,x,a) f(_PP_0 a,x) PP_TRANSFORM_50( f,x,_PP_X a)
...
#define PP_TRANSFORM_99(f,x,a) f(_PP_0 a,x) PP_TRANSFORM_98(f,x,_PP_X a)
#define PP_TRANSFORM_100(f,x,a)f(_PP_0 a,x) PP_TRANSFORM_99(f,x,_PP_X a)

ここPP_NARGで、 は引数の数をカウントするPP_JOINマクロで、 はトークンを結合するマクロ (つまりPP_JOIN(a,b) => ab) です。PP_NARG64 個を超える引数を処理できるようにする場合は、パッチを適用する必要もあります。

さて、元の質問に戻ります。を使用したソリューションPP_TRANSFORMは次のとおりです。

#define FUNCTION(name, dummy) void name();
#define FUNCTION_TABLE(...) PP_TRANSFORM(FUNCTION,dummy,__VA_ARGS__)

C++ 実装関数を生成する場合は、次の不透明な x パラメータを使用できますPP_TRANSFORM

#define FUNCTION_CPP(name, class) void class::name(){}
#define FUNCTION_TABLE_CPP(...) PP_TRANSFORM(FUNCTION_CPP,MyClass,__VA_ARGS__)

これらはすべて、GCC および MSVC プリプロセッサでも同じように機能します。__VA_ARGS__PP_TRANSFORM_NN は、GCC と MSVC の 100 定義の個別の実装を回避するために使用されません

于 2012-11-30T00:50:47.950 に答える