Question

This question is a follow-on from 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

How do I make the macro trick work when passing ellipsis as part of an argument?

Was it helpful?

Solution

The problem isn't with the ellipsis. The problem is that you are passing three arguments in __VA_ARGS__ to DEFINE_REF, but _VA_NARGS_2 only handles up to two arguments.

Once you fix that, the program (I believe) exhibits the desired behavior. gcc 4.7.2 and Clang 3.2 both transform this:

#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      );

into this:

[MyClass] [typename... Args] [Args...];
[MyClass] [typename T] [T];

(Also note that names beginning with an underscore followed by a capital letter are reserved for the implementation. You may not use such names for your own macros.)


If you are targeting Visual C++, you will need a barrel of indirection to make this work, as it does not correctly replace macros before rescanning in all cases. The following will work with Visual C++ (This solution is also conforming and works with gcc and Clang as well):

#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__)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top