C预处理器递归宏

Pav*_*l P 9 c-preprocessor

#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__)))    \
Run Code Online (Sandbox Code Playgroud)

测试代码:

FUNCTION_TABLE(f1, f2,f3,testA,testB,testC);
Run Code Online (Sandbox Code Playgroud)

显然,由于递归扩展,它只会声明void f1(); ,其余的不会扩展:

void f1(); FUNCTION_TABLE(f2,f3,testA,testB,testC);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我可以使用什么样的技巧来实现递归扩展?问题是我需要支持许多参数(最多100个),我绝对不能使用boost.

Pau*_* II 9

最简单的解决方案是使用如下的序列迭代:

#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
Run Code Online (Sandbox Code Playgroud)

然后FUNCTION_TABLE使用预处理器序列而不是varidiac参数调用:

FUNCTION_TABLE((f1)(f2)(f3)(testA)(testB)(testC))
Run Code Online (Sandbox Code Playgroud)

这不仅比使用递归解决方案更简单,更快(即更快的编译)(就像你在这里展示或喜欢这个解决方案).


Pav*_*l P 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)
Run Code Online (Sandbox Code Playgroud)

其中PP_NARG是计算参数数量的宏,PP_JOIN是连接标记的宏(即PP_JOIN(a,b) => ab)。PP_NARG如果您希望能够处理超过 64 个参数,您还需要修补它。

现在,回到原来的问题。使用的解决方案PP_TRANSFORM是:

#define FUNCTION(name, dummy) void name();
#define FUNCTION_TABLE(...) PP_TRANSFORM(FUNCTION,dummy,__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

如果你想生成 C++ 实现函数,那么你可以使用不透明的 x 参数PP_TRANSFORM

#define FUNCTION_CPP(name, class) void class::name(){}
#define FUNCTION_TABLE_CPP(...) PP_TRANSFORM(FUNCTION_CPP,MyClass,__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

所有这些都同样适用于 GCC 和 MSVC 预处理器;PP_TRANSFORM_NN 不用于__VA_ARGS__避免 GCC 和 MSVC 的 100 个定义的单独实现