[ACCEPTED]-Appending to __VA_ARGS__-variadic-macros
Yes, you can. The following supports up 12 to 4 arguments, but it can be trivially 11 expanded to support more:
#define MACRO(api, ...) \
bool ret = api(__VA_ARGS__ VA_COMMA(__VA_ARGS__) 456)
/*
* VA_COMMA() expands to nothing if given no arguments and a comma if
* given 1 to 4 arguments. Bad things happen if given more than 4
* arguments. Don't do it.
*/
#define VA_COMMA(...) GET_6TH_ARG(,##__VA_ARGS__,COMMA,COMMA,COMMA,COMMA,)
#define GET_6TH_ARG(a1,a2,a3,a4,a5,a6,...) a6
#define COMMA ,
/* EXAMPLES */
MACRO(foo) /* bool ret = foo( 456) */
MACRO(foo,1) /* bool ret = foo(1 , 456) */
MACRO(foo,1,2,3,4) /* bool ret = foo(1,2,3,4 , 456) */
/* uh oh, too many arguments: */
MACRO(foo,1,2,3,4,5) /* bool ret = foo(1,2,3,4,5 5 456) */
MACRO(foo,1,2,3,4,5,6) /* bool ret = foo(1,2,3,4,5,6 5 456) */
This same trick 10 is used to:
Explanation
VA_COMMA
surrounds its arguments (__VA_ARGS__
) with 9 six additional arguments: one empty argument 8 before (doesn't have to be empty—it's 7 thrown away) and four commas and an empty 6 argument after.
These six or more arguments 5 are passed to GET_6TH_ARG
, which, as its name implies, expands 4 to the sixth argument. All other arguments 3 are discarded.
Thus, MACRO(foo)
is expanded like this:
step 0: MACRO(foo)
step 1: bool ret = foo( VA_COMMA() 456)
step 2: bool ret = foo( GET_6TH_ARG(,COMMA,COMMA,COMMA,COMMA,) 456)
step 3: bool ret = foo( 456)
MACRO(foo,1)
is 2 expanded like this:
step 0: MACRO(foo,1)
step 1: bool ret = foo(1 VA_COMMA(1) 456)
step 2: bool ret = foo(1 GET_6TH_ARG(,1,COMMA,COMMA,COMMA,COMMA,) 456)
step 3: bool ret = foo(1 COMMA 456)
step 4: bool ret = foo(1 , 456)
MACRO(foo,1,2)
is expanded like this:
step 0: MACRO(foo,1,2)
step 1: bool ret = foo(1,2 VA_COMMA(1,2) 456)
step 2: bool ret = foo(1,2 GET_6TH_ARG(,1,2,COMMA,COMMA,COMMA,COMMA,) 456)
step 3: bool ret = foo(1,2 COMMA 456)
step 4: bool ret = foo(1,2 , 456)
MACRO(foo,1,2,3,4,5)
is 1 expanded like this:
step 0: MACRO(foo,1,2,3,4,5)
step 1: bool ret = foo(1,2,3,4,5 VA_COMMA(1,2,3,4,5) 456)
step 2: bool ret = foo(1,2,3,4,5 GET_6TH_ARG(,1,2,3,4,5,COMMA,COMMA,COMMA,COMMA,) 456)
step 3: bool ret = foo(1,2,3,4,5 5 456)
No. The behaviour of ##
which allows this 6 to work in the first case is a GCC extension 5 (C99 does not allow the variable argument 4 part to be empty), and it specifically applies 3 to the case with a comma on the left and 2 __VA_ARGS__
on the right. See e.g. http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Variadic-Macros.html#Variadic-Macros (at the bottom 1 of the page).
Well, I think it is possible with something 2 like this:
#define NO_FIRST(first, ...) __VA_ARGS__
#define DO_APPEND_LAST(last, ...) NO_FIRST(__VA_ARGS__, last)
#define MACRO(api, ...) bool ret = api(DO_APPEND_LAST(456, dummy, ##__VA_ARGS__));
Haven't check it, however should 1 work in latest VS and gcc.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.