Using PPNARG, I wrote a set of macros to apply a macro to each argument in a macro. I call it a variadic X-macro.
/* * The PP_NARG macro evaluates to the number of arguments that have been * passed to it. * * Laurent Deniau, "__VA_NARG__," 17 January 2006, <comp.std.c> (29 November 2007). */ #define PP_NARG(...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) #define PP_NARG_(...) PP_ARG_N(__VA_ARGS__) #define PP_ARG_N( \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ _61,_62,_63,N,...) N #define PP_RSEQ_N() \ 63,62,61,60, \ 59,58,57,56,55,54,53,52,51,50, \ 49,48,47,46,45,44,43,42,41,40, \ 39,38,37,36,35,34,33,32,31,30, \ 29,28,27,26,25,24,23,22,21,20, \ 19,18,17,16,15,14,13,12,11,10, \ 9,8,7,6,5,4,3,2,1,0
PPNARG lets us get a count of how many arguments there are. Then we append that number to the macro name and call it with the original arguments.
/* need extra level to force extra eval */ #define Paste(a,b) a ## b #define XPASTE(a,b) Paste(a,b) /* APPLYXn variadic X-Macro by M Joshua Ryan */ /* Free for all uses. Don't be a jerk. */ /* I got bored after typing 15 of these. */ /* You could keep going upto 64 (PPNARG's limit). */ #define APPLYX1(a) X(a) #define APPLYX2(a,b) X(a) X(b) #define APPLYX3(a,b,c) X(a) X(b) X(c) #define APPLYX4(a,b,c,d) X(a) X(b) X(c) X(d) #define APPLYX5(a,b,c,d,e) X(a) X(b) X(c) X(d) X(e) #define APPLYX6(a,b,c,d,e,f) X(a) X(b) X(c) X(d) X(e) X(f) #define APPLYX7(a,b,c,d,e,f,g) \ X(a) X(b) X(c) X(d) X(e) X(f) X(g) #define APPLYX8(a,b,c,d,e,f,g,h) \ X(a) X(b) X(c) X(d) X(e) X(f) X(g) X(h) #define APPLYX9(a,b,c,d,e,f,g,h,i) \ X(a) X(b) X(c) X(d) X(e) X(f) X(g) X(h) X(i) #define APPLYX10(a,b,c,d,e,f,g,h,i,j) \ X(a) X(b) X(c) X(d) X(e) X(f) X(g) X(h) X(i) X(j) #define APPLYX11(a,b,c,d,e,f,g,h,i,j,k) \ X(a) X(b) X(c) X(d) X(e) X(f) X(g) X(h) X(i) X(j) X(k) #define APPLYX12(a,b,c,d,e,f,g,h,i,j,k,l) \ X(a) X(b) X(c) X(d) X(e) X(f) X(g) X(h) X(i) X(j) X(k) X(l) #define APPLYX13(a,b,c,d,e,f,g,h,i,j,k,l,m) \ X(a) X(b) X(c) X(d) X(e) X(f) X(g) X(h) X(i) X(j) X(k) X(l) X(m) #define APPLYX14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) \ X(a) X(b) X(c) X(d) X(e) X(f) X(g) X(h) X(i) X(j) X(k) X(l) X(m) X(n) #define APPLYX15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) \ X(a) X(b) X(c) X(d) X(e) X(f) X(g) X(h) X(i) X(j) X(k) X(l) X(m) X(n) X(o) #define APPLYX_(M, ...) M(__VA_ARGS__) #define APPLYXn(...) APPLYX_(XPASTE(APPLYX, PP_NARG(__VA_ARGS__)), __VA_ARGS__)
And here are some examples with the output from gcc -E in comments.
/* Example */ #define X(a) #a, char *list[] = { APPLYXn(sugar,coffee,drink,smoke) }; #undef X /* Produces (gcc -E) char *list[] = { "sugar", "coffee", "drink", "smoke", }; */ #define c1(a) case a: #define c2(a,b) c1(a) c1(b) #define c3(a,b,c) c1(a) c2(b,c) #define c4(a,b,c,d) c1(a) c3(b,c,d) #define c_(M, ...) M(__VA_ARGS__) #define cases(...) c_(XPASTE(c, PP_NARG(__VA_ARGS__)), __VA_ARGS__) //cases(3,4,5,6,7) //produces //case 3: case 4: case 5: case 6: #define r_(a,b) range(a,b) #define range(a,b) a,r_(a+1,b-1) //range(3,4) #define ps1(a) O ## a (); #define ps2(a,b) ps1(a) ps1(b) #define ps3(a,b,c) ps1(a) ps2(b,c) #define ps4(a,b,c,d) ps1(a) ps3(b,c,d) #define ps_(M, ...) M(__VA_ARGS__) #define ps(...) ps_(XPASTE(ps, PP_NARG(__VA_ARGS__)), __VA_ARGS__) //ps(dup,add,sub)
This last was the motive for the whole thing. But it didn't turn out to be very useful.
Edit: many years later...
If we take a step back and reimagine the goal "apply a macro to each argument of a macro", this ia almost the same thing as an X-Macro. And I think an X-Macro can be made to do roughly the same job with a slight difference in syntax.
#define EACH_THING(X) \ X(Thing1) \ X(Thing2) \ X(OtherThing) \ /**/
Then you can write a macro that deals with each thing individually and by invoking the EACH_* with the name of the macro to use.
#define BareWord_comma(X) X , #define String_comma(X) #X , enum{ EACH_THING( BareWord_comma ) NUM_THINGS }; char*names[]={ EACH_THING( String_comma ) NULL };
Here the list of things isn't the argument list to a macro, but a sequence of macro invocations in the body of a macro. The important parts are all here, though: separating the list of things from the transformation to apply to each one.