問題は省略記号ではありません。__VA_ARGS__
問題は、に3つの引数を渡していますがDEFINE_REF
、_VA_NARGS_2
処理できるのは最大2つの引数だけであるということです。
これを修正すると、プログラム(私は信じています)は望ましい動作を示します。gcc4.7.2とClang3.2はどちらもこれを変換します。
#define DEFINE_REF_INTERNAL3(arg0, arg1, arg2) [arg0] [arg1] [arg2]
#define VA_NARGS_(_1, _2, _3, N, ...) N
#define VA_NARGS(...) VA_NARGS_(__VA_ARGS__, 3, 2, 1)
#define DEFINE_REF_IMPL_(count, ...) DEFINE_REF_INTERNAL ## count(__VA_ARGS__)
#define DEFINE_REF_IMPL(count, ...) DEFINE_REF_IMPL_(count, __VA_ARGS__)
#define DEFINE_REF(...) DEFINE_REF_IMPL(VA_NARGS(__VA_ARGS__), __VA_ARGS__)
DEFINE_REF(MyClass, typename... Args, Args...);
DEFINE_REF(MyClass, typename T, T );
これに:
[MyClass] [typename... Args] [Args...];
[MyClass] [typename T] [T];
(アンダースコアで始まり大文字が続く名前は実装用に予約されていることにも注意してください。このような名前を独自のマクロに使用することはできません。)
Visual C ++を対象としている場合、すべての場合に再スキャンする前にマクロが正しく置き換えられないため、これを機能させるには間接参照のバレルが必要になります。以下はVisualC++で動作します(このソリューションは準拠しており、gccとClangでも動作します):
#define DEFINE_REF_INTERNAL3(id, arg0, arg1) id [arg0] [arg1]
#define CONCATENATE_(x, y) x ## y
#define CONCATENATE(x, y) CONCATENATE_(x, y)
#define VA_NARGS1(_1, _2, _3, N, ...) N
#define VA_NARGS0(x) VA_NARGS1 x
#define VA_NARGS(...) VA_NARGS0((__VA_ARGS__, 3, 2, 1))
#define DEFINE_REF_IMPL1(macro, pargs) macro pargs
#define DEFINE_REF_IMPL0(count, ...) \
DEFINE_REF_IMPL1(CONCATENATE(DEFINE_REF_INTERNAL, count), (__VA_ARGS__))
#define DEFINE_REF_IMPL(count, ...) DEFINE_REF_IMPL0(count, __VA_ARGS__)
#define DEFINE_REF(...) DEFINE_REF_IMPL(VA_NARGS(__VA_ARGS__), __VA_ARGS__)