#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__))) \
test code:
FUNCTION_TABLE(f1, f2,f3,testA,testB,testC);
Obviously, because of recursive expansion it will only declare void f1();
and the rest won't be expanded:
void f1(); FUNCTION_TABLE(f2,f3,testA,testB,testC);
What kind of trick can I use to achieve recursive expansion in this case? The problem is that I need to support MANY arguments (up 100) and I absolutely cannot use boost.
The simplest solution is to use sequence iteration like this:
#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
Then you call FUNCTION_TABLE
with a preprocessor sequence instead of varidiac arguments:
FUNCTION_TABLE((f1)(f2)(f3)(testA)(testB)(testC))
Not only is this much simpler, its also faster(ie faster compilation) than using the recursive solution(like the one you've shown or like this one here).
Here's the answer in case somebody wants to do the same.
#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)
where PP_NARG
is the macro that counts number of arguments and PP_JOIN
is the macro that joins tokens (that is PP_JOIN(a,b) => ab
). You'll also need to patch that PP_NARG
if you want to be able to process more than 64 arguments.
Now, back to the original question. Solution using the PP_TRANSFORM
is:
#define FUNCTION(name, dummy) void name();
#define FUNCTION_TABLE(...) PP_TRANSFORM(FUNCTION,dummy,__VA_ARGS__)
if you want to generate c++ implementation functions then you can use that opaque x parameter of PP_TRANSFORM
:
#define FUNCTION_CPP(name, class) void class::name(){}
#define FUNCTION_TABLE_CPP(...) PP_TRANSFORM(FUNCTION_CPP,MyClass,__VA_ARGS__)
All this works equally well with GCC and MSVC preprocessors; PP_TRANSFORM_NN doesn't use __VA_ARGS__
to avoid separate implementations of 100 defines for GCC and MSVC
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With