16

我知道我可以这样做:

#define MACRO(api, ...) \
  bool ret = api(123, ##__VA_ARGS__);

这只是一个示例,它是更复杂解决方案的一部分。关键是我需要将可变数量的参数附加到前 123 个参数中。如果没有将参数传递给 MACRO,## 会使编译器在 123 参数之后去掉逗号。

但现在我想将参数附加到 api,如下所示:

#define MACRO(api, ...) \
  bool ret = api(__VA_ARGS__##, 456);

诺坎多。一种解决方案是使用两个宏,例如 MACRO 和 MACRO_V,并使 _V 版本不处理任何参数。但是有没有办法让它与一个宏一起工作?

4

3 回答 3

21

是的你可以。以下支持最多 4 个参数,但可以轻松扩展以支持更多:

#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) */

同样的技巧用于:

解释

VA_COMMA用六个附加参数包围它的参数 ( __VA_ARGS__):一个空参数之前(不必为空 - 它被丢弃)和四个逗号和一个空参数之后。

这六个或更多参数被传递给GET_6TH_ARG,顾名思义,它扩展到第六个参数。所有其他参数都被丢弃。

因此,MACRO(foo)展开如下:

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)展开如下:

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)展开如下:

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)展开如下:

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)
于 2012-02-09T03:18:41.417 回答
4

不。允许它在第一种情况下工作的行为##是 GCC 扩展(C99 不允许变量参数部分为空),它特别适用于左右有逗号的情况__VA_ARGS__。参见例如http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Variadic-Macros.html#Variadic-Macros(在页面底部)。

于 2010-11-04T22:43:59.423 回答
3

好吧,我认为这样的事情是可能的:

#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__));

没有检查它,但是应该在最新的 VS 和 gcc 中工作。

于 2014-03-14T13:50:22.260 回答