16

私はこれができることを知っています:

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

これは単なる例であり、より複雑なソリューションの一部です。ポイントは、可変数の引数を最初の 123 に追加する必要があるということです。引数が MACRO に渡されない場合、## により、コンパイラは 123 引数の後のコンマを削除します。

しかし、次のように引数を api に追加したいと思います。

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

ノカンド。1 つの解決策は、たとえば MACRO と MACRO_V という 2 つのマクロを用意し、_V バージョンでは引数を処理しないようにすることです。しかし、1 つのマクロで動作させる方法はありますか?

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__) を 6 つの追加の引数で囲みます。前に 1 つの空の引数 (空である必要はありません。破棄されます) と、4 つのコンマと後の空の引数です。

これらの 6 つ以上の引数は に渡されGET_6TH_ARG、その名前が示すように、6 番目の引数に展開されます。他のすべての引数は破棄されます。

したがって、次のように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 に答える