C++ – Is it possible to pass a brace-enclosed initializer as a macro parameter

cc-preprocessorc++11language-lawyer

I have a function that I call like this:

literal<long[2]>({1, 2});

I want to write a macro that expands to this statement, e.g.:

MYMACRO(long[2], {1, 2})

Unfortunately, the preprocessor is not aware of brace-matching so it sees three arguments (the second and third are {1 and 2}, respectively).

This is a known limitation of the preprocessor, and the simplest solution is often to add extra parentheses, if possible, in the macro invocation.

But, in this case, placing the brace-enclosed initializer inside parentheses appears to change its meaning:

literal<long[2]>(({1, 2}));

(g++ 4.8) error: left operand of comma operator has no effect [-Werror=unused-value]

Is this a GCC bug or correct by design? Is there any way to accomplish what I want?

Update

I probably should have been more clear in the phrasing of the original questions. The preprocessor hasn't changed in forever (even variadic macros have been a GCC extension for a long time). The practical workarounds in this case are useful, but they're also very well known and not to the point I want to get at.

I really want to know whether anything was added to C++11 to specifically address this issue (or was it an oversight?). The quirky handling of braces in macro invocations seems like a much bigger issue now, given the greatly expanded use of brace-enclosed lists throughout the language.

I'm especially annoyed by the fact that putting parentheses around a brace-enclosed initializer list changes the way it's parsed when used as a function parameter. Is there any other parameter to a function invocation that cannot be parenthesized? It seems like special-case hell when writing macros that pass parameters to functions.

I'm really hoping somebody can point out that this is a GCC bug, or explain why putting parentheses around a brace-enclosed initializer list must change its meaning.

Best Answer

You can use __VA_ARGS__:

#define MYMACRO(T,...) literal<T>(__VA_ARGS__);

In case you have more parameters, you can use an indirection:

#define UNWRAP(...) __VA_ARGS__
#define MYMACRO(T,A) literal<T>(UNWRAP A);

and now you can use

MYMACRO( long[2], ({1, 2}) )

Updated answer

You could also, if you like, replace the curly brackets in the invocation of the macro with the round brackets:

#define BRACED_INIT_LIST(...) {__VA_ARGS__}
#define MYMACRO(T,A) literal<T>(BRACED_INIT_LIST A);

and call

MYMACRO( long[2], (1, 2) )

which is IMHO consistent with typical macro-invocation-styles.

Some words on your other questions: The preprocessor knows nothing about the language (C, C++, C++11) and hence should not care about the special meaning of symbols. It is tracking round brackets, but almost everything else is just tokens.

I also think it's not an oversight from the standard committee as the focus should be on making the use of the preprocessor superfluous for most cases. Have you considered other (non-macro) techniques to implement MYMACRO? Also, work-arounds for the remaining use-cases (as shown above) are certainly possible.

Finally, it is certainly not a bug in GCC as the compiler simply implements what the standard says.

Related Topic