使用省略号计算参数的变量模板作为参数传递

时间:2012-12-14 00:52:15

标签: c++ macros c-preprocessor variadic-macros

此问题是https://stackoverflow.com/a/5365786/383306的后续问题。

#define _DEFINE_REF_INTERNAL2(id, ...)

#define _DEFINE_REF_INTERNAL1(id)

#define _VA_NARGS_2_IMPL(_1, _2, N, ...) N
#define _VA_NARGS_2(...) _VA_NARGS_2_IMPL(__VA_ARGS__, 2, 1)
#define _DEFINE_REF_IMPL2(count, ...) _DEFINE_REF_INTERNAL ## count (__VA_ARGS__)
#define _DEFINE_REF_IMPL(count, ...) _DEFINE_REF_IMPL2(count, __VA_ARGS__)
#define DEFINE_REF(...) _DEFINE_REF_IMPL(_VA_NARGS_2(__VA_ARGS__), __VA_ARGS__)

DEFINE_REF(MyClass, typename... Args, Args...); 
// error: ‘_DEFINE_REF_INTERNALArgs’ does not name a type
DEFINE_REF(MyClass, typename T, T); // this is OK

如果将省略号作为参数的一部分传递,我如何使宏技巧工作?

1 个答案:

答案 0 :(得分:1)

问题不在于省略号。问题是您将__VA_ARGS__中的三个参数传递给DEFINE_REF,但_VA_NARGS_2仅处理最多两个参数。

一旦你解决了这个问题,程序(我相信)会表现出理想的行为。 gcc 4.7.2和Clang 3.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 ++,则需要一个间接桶才能使其正常工作,因为在所有情况下重新扫描之前它都无法正确替换宏。以下内容适用于Visual C ++(此解决方案也符合并适用于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__)