ネットで答えが見つからなかった簡単な質問。可変個引数マクロで、引数の数を見つける方法は?解決策があれば、ブーストプリプロセッサーで大丈夫です。
それが違いを生む場合、可変数のマクロ引数を変換して、プリプロセッサのシーケンス、リスト、または配列をブーストして、さらに再処理します。
__typeof__
、少なくとも一部のコンパイラで機能させることができます
ネットで答えが見つからなかった簡単な質問。可変個引数マクロで、引数の数を見つける方法は?解決策があれば、ブーストプリプロセッサーで大丈夫です。
それが違いを生む場合、可変数のマクロ引数を変換して、プリプロセッサのシーケンス、リスト、または配列をブーストして、さらに再処理します。
__typeof__
、少なくとも一部のコンパイラで機能させることができます
回答:
これは実際にはコンパイラに依存しており、どの規格でもサポートされていません。
ただし、ここではカウントを行うマクロ実装があります。
#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
/* Some test cases */
PP_NARG(A) -> 1
PP_NARG(A,B) -> 2
PP_NARG(A,B,C) -> 3
PP_NARG(A,B,C,D) -> 4
PP_NARG(A,B,C,D,E) -> 5
PP_NARG(1,2,3,4,5,6,7,8,9,0,
1,2,3,4,5,6,7,8,9,0,
1,2,3,4,5,6,7,8,9,0,
1,2,3,4,5,6,7,8,9,0,
1,2,3,4,5,6,7,8,9,0,
1,2,3,4,5,6,7,8,9,0,
1,2,3) -> 63
#define EXPAND(x) x
#define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, 9,8,7,6,5,4,3,2,1,0))
`` `
PP_NARG()
0ザ・返すことに失敗したGET_ARG_COUNT()
&Y_TUPLE_SIZE()
ソリューションの仕事を。
PP_NARG()
は0を返しません...は必ずしも問題ではありません。同じ理由で1を返す必要がある場合は2を返すPP_NARG()
必要があると言えますPP_NARG(,)
。 実際に0を検出すると便利な場合がありますが、解決策は一般的ではないようです(最初のトークンを貼り付け可能にする必要があるため、問題ない場合もあります)。使用目的に応じて)、または実装固有(gnuのコンマ削除ペーストトリックが必要など)。
私は通常、このマクロを使用して多数のパラメーターを検索します。
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
完全な例:
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define SUM(...) (sum(NUMARGS(__VA_ARGS__), __VA_ARGS__))
void sum(int numargs, ...);
int main(int argc, char *argv[]) {
SUM(1);
SUM(1, 2);
SUM(1, 2, 3);
SUM(1, 2, 3, 4);
return 1;
}
void sum(int numargs, ...) {
int total = 0;
va_list ap;
printf("sum() called with %d params:", numargs);
va_start(ap, numargs);
while (numargs--)
total += va_arg(ap, int);
va_end(ap);
printf(" %d\n", total);
return;
}
完全に有効なC99コードです。ただし、1つの欠点がありますSUM()
。paramsなしではマクロを呼び出せませんが、GCCには解決策があります。こちらを参照してください。
したがって、GCCの場合、次のようなマクロを定義する必要があります。
#define NUMARGS(...) (sizeof((int[]){0, ##__VA_ARGS__})/sizeof(int)-1)
#define SUM(...) sum(NUMARGS(__VA_ARGS__), ##__VA_ARGS__)
そしてそれは空のパラメーターリストでも動作します
sizeof(int) != sizeof(void *)
ますか?
{__VA_ARGS__}
したので、実際の内容に関係なくint[]
、それだけint[]
です__VA_ARGS__
##
空__VA_ARGS__
は先行するコンマを自動的に削除するため、VS2017ではこれは必要ありません。
C ++ 11を使用していて、C ++コンパイル時定数として値が必要な場合、非常にエレガントな解決策は次のとおりです。
#include <tuple>
#define MACRO(...) \
std::cout << "num args: " \
<< std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value \
<< std::endl;
注意:カウントはコンパイル時に完全に行われ、値はコンパイル時の整数が必要なときにいつでも使用できます。たとえば、std :: arrayのテンプレートパラメーターとして使用できます。
sizeof((int[]){__VA_ARGS__})/sizeof(int)
上記の提案とは異なり、引数をすべてにキャストできない場合でも機能しint
ます。
#define NUM_ARGS(...) std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value
便宜上、0〜70個の引数で機能し、Visual Studio、GCC、およびClangで機能する実装を次に示します。Visual Studio 2010以降で機能すると思いますが、VS2013でのみテストしました。
#ifdef _MSC_VER // Microsoft compilers
# define GET_ARG_COUNT(...) INTERNAL_EXPAND_ARGS_PRIVATE(INTERNAL_ARGS_AUGMENTER(__VA_ARGS__))
# define INTERNAL_ARGS_AUGMENTER(...) unused, __VA_ARGS__
# define INTERNAL_EXPAND(x) x
# define INTERNAL_EXPAND_ARGS_PRIVATE(...) INTERNAL_EXPAND(INTERNAL_GET_ARG_COUNT_PRIVATE(__VA_ARGS__, 69, 68, 67, 66, 65, 64, 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))
# define INTERNAL_GET_ARG_COUNT_PRIVATE(_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, _64, _65, _66, _67, _68, _69, _70, count, ...) count
#else // Non-Microsoft compilers
# define GET_ARG_COUNT(...) INTERNAL_GET_ARG_COUNT_PRIVATE(0, ## __VA_ARGS__, 70, 69, 68, 67, 66, 65, 64, 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)
# define INTERNAL_GET_ARG_COUNT_PRIVATE(_0, _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, _64, _65, _66, _67, _68, _69, _70, count, ...) count
#endif
static_assert(GET_ARG_COUNT() == 0, "GET_ARG_COUNT() failed for 0 arguments");
static_assert(GET_ARG_COUNT(1) == 1, "GET_ARG_COUNT() failed for 1 argument");
static_assert(GET_ARG_COUNT(1,2) == 2, "GET_ARG_COUNT() failed for 2 arguments");
static_assert(GET_ARG_COUNT(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, 64, 65, 66, 67, 68, 69, 70) == 70, "GET_ARG_COUNT() failed for 70 arguments");
__VA_ARGS__
」(C ++では技術的には(ほぼ普遍的な事実上の標準)コンパイラ拡張であり、C ++ 20まで)について少し優れているためだと思います。ほとんどの(すべて?)コンパイラーは長さゼロを許可しますが、リストが空の場合(そして、この場合、コンマを削除するために##
proto-としてオーバーロードします)、末尾のコンマを抑制します__VA_OPT__
。拡張機能のMSVCのバージョンは、単にカンマで窒息しない(しかしますオーバーロードされた上でチョーク##
)。MSVC unused, __VA_ARGS__
と非MSVC を比較し0, ## __VA_ARGS__
ます。どちらも正確ではありませんが、問題はそれらが異なることです。
コンパイル時に引数の数を見つけるためのC ++ 11ソリューションはいくつかありますが、次のような単純なことを提案した人がいないことに驚いています。
#define VA_COUNT(...) detail::va_count(__VA_ARGS__)
namespace detail
{
template<typename ...Args>
constexpr std::size_t va_count(Args&&...) { return sizeof...(Args); }
}
これには、<tuple>
ヘッダーを含める必要もありません。
VA_COUNT(&,^,%)
。また、関数を使用してカウントしている場合は、マクロを作成する意味がありません。
これはgcc / llvmで0引数で動作します。[リンクはばかげている]
/*
* we need a comma at the start for ##_VA_ARGS__ to consume then
* the arguments are pushed out in such a way that 'cnt' ends up with
* the right count.
*/
#define COUNT_ARGS(...) COUNT_ARGS_(,##__VA_ARGS__,6,5,4,3,2,1,0)
#define COUNT_ARGS_(z,a,b,c,d,e,f,cnt,...) cnt
#define C_ASSERT(test) \
switch(0) {\
case 0:\
case test:;\
}
int main() {
C_ASSERT(0 == COUNT_ARGS());
C_ASSERT(1 == COUNT_ARGS(a));
C_ASSERT(2 == COUNT_ARGS(a,b));
C_ASSERT(3 == COUNT_ARGS(a,b,c));
C_ASSERT(4 == COUNT_ARGS(a,b,c,d));
C_ASSERT(5 == COUNT_ARGS(a,b,c,d,e));
C_ASSERT(6 == COUNT_ARGS(a,b,c,d,e,f));
return 0;
}
Visual Studioは、空の引数を消費するために使用される##演算子を無視しているようです。あなたはおそらく次のようなものでそれを回避することができます
#define CNT_ COUNT_ARGS
#define PASTE(x,y) PASTE_(x,y)
#define PASTE_(x,y) x ## y
#define CNT(...) PASTE(ARGVS,PASTE(CNT_(__VA_ARGS__),CNT_(1,##__VA_ARGS__)))
//you know its 0 if its 11 or 01
#define ARGVS11 0
#define ARGVS01 0
#define ARGVS12 1
#define ARGVS23 2
#define ARGVS34 3
##__VA_ARGS__
前にコンマを食べるの__VA_ARGS__
はGCC拡張です。これは標準的な動作ではありません。
msvc拡張あり:
#define Y_TUPLE_SIZE(...) Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX,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))
#define Y_TUPLE_SIZE_II(__args) Y_TUPLE_SIZE_I __args
#define Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
#define Y_TUPLE_SIZE_I(__p0,__p1,__p2,__p3,__p4,__p5,__p6,__p7,__p8,__p9,__p10,__p11,__p12,__p13,__p14,__p15,__p16,__p17,__p18,__p19,__p20,__p21,__p22,__p23,__p24,__p25,__p26,__p27,__p28,__p29,__p30,__p31,__n,...) __n
0-32の引数で機能します。この制限は簡単に拡張できます。
編集:簡略化されたバージョン(VS2015 14.0.25431.01 Update 3およびgcc 7.4.0で機能)まで最大100個の引数をコピーして貼り付けます。
#define COUNTOF(...) _COUNTOF_CAT( _COUNTOF_A, ( 0, ##__VA_ARGS__, 100,\
99, 98, 97, 96, 95, 94, 93, 92, 91, 90,\
89, 88, 87, 86, 85, 84, 83, 82, 81, 80,\
79, 78, 77, 76, 75, 74, 73, 72, 71, 70,\
69, 68, 67, 66, 65, 64, 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 ) )
#define _COUNTOF_CAT( a, b ) a b
#define _COUNTOF_A( a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,\
a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,\
a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,\
a30, a31, a32, a33, a34, a35, a36, a37, a38, a39,\
a40, a41, a42, a43, a44, a45, a46, a47, a48, a49,\
a50, a51, a52, a53, a54, a55, a56, a57, a58, a59,\
a60, a61, a62, a63, a64, a65, a66, a67, a68, a69,\
a70, a71, a72, a73, a74, a75, a76, a77, a78, a79,\
a80, a81, a82, a83, a84, a85, a86, a87, a88, a89,\
a90, a91, a92, a93, a94, a95, a96, a97, a98, a99,\
a100, n, ... ) n
Y_TUPLE_SIZE("Hello")
非常に実行不可能です。@osirisgothraに同意します。
VA_ARGSの各引数はカンマで区切られていると想定しています。もしそうなら、これはこれを行うためのかなりクリーンな方法として機能するはずだと思います。
#include <cstring>
constexpr int CountOccurances(const char* str, char c) {
return str[0] == char(0) ? 0 : (str[0] == c) + CountOccurances(str+1, c);
}
#define NUMARGS(...) (CountOccurances(#__VA_ARGS__, ',') + 1)
int main(){
static_assert(NUMARGS(hello, world) == 2, ":(") ;
return 0;
}
clang 4とGCC 5.1のgodboltで私のために働いた。これはコンパイル時に計算されますが、プリプロセッサに対しては評価されません。したがって、FOR_EACHを作成するようなことを行おうとすると、これは機能しません。
NUMARGS(hello, world = 2, ohmy42, !@#$%^&*()-+=)
!!! 各引数の文字列は、いくつかの他のシンボルのようなことはできません','
けれども
int count = NUMARGS( foo(1, 2) );
1ではなく2を生成するため、括弧を微調整する必要があります 。godbolt.org
ここではVA_ARGSの 0個以上の引数をカウントする簡単な方法ですが、私の例では最大5つの変数を想定していますが、必要に応じてさらに追加できます。
#define VA_ARGS_NUM_PRIV(P1, P2, P3, P4, P5, P6, Pn, ...) Pn
#define VA_ARGS_NUM(...) VA_ARGS_NUM_PRIV(-1, ##__VA_ARGS__, 5, 4, 3, 2, 1, 0)
VA_ARGS_NUM() ==> 0
VA_ARGS_NUM(19) ==> 1
VA_ARGS_NUM(9, 10) ==> 2
...
VA_ARGS_NUM
マクロで使用されている:私が持っている場合#define TEST
(つまり空TEST
)とVA_ARGS_NUM(TEST)
0(ゼロ)で使用戻らない#if
:(を
トークンをストリング化してカウントできます。
int countArgs(char *args)
{
int result = 0;
int i = 0;
while(isspace(args[i])) ++i;
if(args[i]) ++result;
while(args[i]) {
if(args[i]==',') ++result;
else if(args[i]=='\'') i+=2;
else if(args[i]=='\"') {
while(args[i]) {
if(args[i+1]=='\"' && args[i]!='\\') {
++i;
break;
}
++i;
}
}
++i;
}
return result;
}
#define MACRO(...) \
{ \
int count = countArgs(#__VA_ARGS__); \
printf("NUM ARGS: %d\n",count); \
}
Boost Preprocessorには、Boost 1.49の時点で実際にこれがありBOOST_PP_VARIADIC_SIZE(...)
ます。サイズ64まで動作します。
内部的には、Kornel Kisielewiczの回答と基本的に同じです。
ここでの回答はまだ不完全であることがわかりました。
私がここから見つけた最も近いポータブルな実装は次のとおりです: C ++プリプロセッサ__VA_ARGS__引数の数
ただし、GCCのゼロ引数では、少なくとも-std=gnu++11
コマンドラインパラメータがなければ機能しません。
そこで、私はこのソリューションをそれとマージすることにしました:https : //gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
#define UTILITY_PP_CONCAT_(v1, v2) v1 ## v2
#define UTILITY_PP_CONCAT(v1, v2) UTILITY_PP_CONCAT_(v1, v2)
#define UTILITY_PP_CONCAT5_(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define UTILITY_PP_IDENTITY_(x) x
#define UTILITY_PP_IDENTITY(x) UTILITY_PP_IDENTITY_(x)
#define UTILITY_PP_VA_ARGS_(...) __VA_ARGS__
#define UTILITY_PP_VA_ARGS(...) UTILITY_PP_VA_ARGS_(__VA_ARGS__)
#define UTILITY_PP_IDENTITY_VA_ARGS_(x, ...) x, __VA_ARGS__
#define UTILITY_PP_IDENTITY_VA_ARGS(x, ...) UTILITY_PP_IDENTITY_VA_ARGS_(x, __VA_ARGS__)
#define UTILITY_PP_IIF_0(x, ...) __VA_ARGS__
#define UTILITY_PP_IIF_1(x, ...) x
#define UTILITY_PP_IIF(c) UTILITY_PP_CONCAT_(UTILITY_PP_IIF_, c)
#define UTILITY_PP_HAS_COMMA(...) UTILITY_PP_IDENTITY(UTILITY_PP_VA_ARGS_TAIL(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0))
#define UTILITY_PP_IS_EMPTY_TRIGGER_PARENTHESIS_(...) ,
#define UTILITY_PP_IS_EMPTY(...) UTILITY_PP_IS_EMPTY_( \
/* test if there is just one argument, eventually an empty one */ \
UTILITY_PP_HAS_COMMA(__VA_ARGS__), \
/* test if _TRIGGER_PARENTHESIS_ together with the argument adds a comma */ \
UTILITY_PP_HAS_COMMA(UTILITY_PP_IS_EMPTY_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
/* test if the argument together with a parenthesis adds a comma */ \
UTILITY_PP_HAS_COMMA(__VA_ARGS__ ()), \
/* test if placing it between _TRIGGER_PARENTHESIS_ and the parenthesis adds a comma */ \
UTILITY_PP_HAS_COMMA(UTILITY_PP_IS_EMPTY_TRIGGER_PARENTHESIS_ __VA_ARGS__ ()))
#define UTILITY_PP_IS_EMPTY_(_0, _1, _2, _3) UTILITY_PP_HAS_COMMA(UTILITY_PP_CONCAT5_(UTILITY_PP_IS_EMPTY_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define UTILITY_PP_IS_EMPTY_IS_EMPTY_CASE_0001 ,
#define UTILITY_PP_VA_ARGS_SIZE(...) UTILITY_PP_IIF(UTILITY_PP_IS_EMPTY(__VA_ARGS__))(0, UTILITY_PP_VA_ARGS_SIZE_(__VA_ARGS__, UTILITY_PP_VA_ARGS_SEQ64()))
#define UTILITY_PP_VA_ARGS_SIZE_(...) UTILITY_PP_IDENTITY(UTILITY_PP_VA_ARGS_TAIL(__VA_ARGS__))
#define UTILITY_PP_VA_ARGS_TAIL(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14, x, ...) x
#define UTILITY_PP_VA_ARGS_SEQ64() 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
#define EATER0(...)
#define EATER1(...) ,
#define EATER2(...) (/*empty*/)
#define EATER3(...) (/*empty*/),
#define EATER4(...) EATER1
#define EATER5(...) EATER2
#define MAC0() ()
#define MAC1(x) ()
#define MACV(...) ()
#define MAC2(x,y) whatever
static_assert(UTILITY_PP_VA_ARGS_SIZE() == 0, "1");
static_assert(UTILITY_PP_VA_ARGS_SIZE(/*comment*/) == 0, "2");
static_assert(UTILITY_PP_VA_ARGS_SIZE(a) == 1, "3");
static_assert(UTILITY_PP_VA_ARGS_SIZE(a, b) == 2, "4");
static_assert(UTILITY_PP_VA_ARGS_SIZE(a, b, c) == 3, "5");
static_assert(UTILITY_PP_VA_ARGS_SIZE(a, b, c, d) == 4, "6");
static_assert(UTILITY_PP_VA_ARGS_SIZE(a, b, c, d, e) == 5, "7");
static_assert(UTILITY_PP_VA_ARGS_SIZE((void)) == 1, "8");
static_assert(UTILITY_PP_VA_ARGS_SIZE((void), b, c, d) == 4, "9");
static_assert(UTILITY_PP_VA_ARGS_SIZE(UTILITY_PP_IS_EMPTY_TRIGGER_PARENTHESIS_) == 1, "10");
static_assert(UTILITY_PP_VA_ARGS_SIZE(EATER0) == 1, "11");
static_assert(UTILITY_PP_VA_ARGS_SIZE(EATER1) == 1, "12");
static_assert(UTILITY_PP_VA_ARGS_SIZE(EATER2) == 1, "13");
static_assert(UTILITY_PP_VA_ARGS_SIZE(EATER3) == 1, "14");
static_assert(UTILITY_PP_VA_ARGS_SIZE(EATER4) == 1, "15");
static_assert(UTILITY_PP_VA_ARGS_SIZE(MAC0) == 1, "16");
// a warning in msvc
static_assert(UTILITY_PP_VA_ARGS_SIZE(MAC1) == 1, "17");
static_assert(UTILITY_PP_VA_ARGS_SIZE(MACV) == 1, "18");
// This one will fail because MAC2 is not called correctly
//static_assert(UTILITY_PP_VA_ARGS_SIZE(MAC2) == 1, "19");
c++11
、msvc 2015
、gcc 4.7.1
、clang 3.0