Этот вопрос является продолжением 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
Как заставить трюк макроса работать при передаче многоточия в качестве аргумента?
Проблема не в многоточии. Проблема в том, что вы передаете три аргумента в __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__)
Других решений пока нет …