7

I found a question showing how to overload macros based on the number of arguments : Overloading Macro on Number of Arguments

But as they say, it's not working using MSVC because MSVC expands __VA_ARGS__ into a single token instead of a list of arguments (arg1, arg2, arg3).

They point to another question where a work around is given : MSVC doesn't expand __VA_ARGS__ correctly But not explained at all, so I can't adapt it to my own case since I can't understand it.

Could you please explain how this workaround works ?

Community
  • 1
  • 1
Virus721
  • 8,061
  • 12
  • 67
  • 123

1 Answers1

14

The workaround in question is this:

#define EXPAND( x ) x
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) EXPAND( F(__VA_ARGS__) )

The idea is that given an existing variadic macro F():

#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__

instead of writing your desired variadic wrapper macro as, in this case, ...

#define G(...) F(__VA_ARGS__)

... you write G() with use of the additional EXPAND() macro. The actual definition of F() is not the point, and in particular it doesn't matter for this example that macro expansion does not produce valid C code. Its purpose is to demonstrate the preprocessor's behavior with respect to macro arguments. Specifically, it shows that although MSVC expands __VA_ARGS__ to a single token in a variadic macro, that can be worked around by forcing a double expansion.

For example, using the workaround definition, the preprocessor first expands ...

G(1, 2, 3)

... to ...

EXPAND( F(1, 2, 3) )

... where the 1, 2, 3 is treated as a single token. That tokenization no longer matters when the preprocessor rescans for additional replacements, however: it sees the 1, 2, 3 as separate arguments to macro F(), and expands that as desired to produce the argument to macro EXPAND(), which just replaces it with itself.

If you think it odd that this works as intended, but the version without EXPAND() does not work (in MSVC), you are right.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • It works, thanks. I also understand it better now. Calling the macro where the arguments are supposed to be expanded using another macro causes the compiler to expand the arguments correctly. – Virus721 Sep 07 '15 at 07:43
  • Actually my case is little bit different. I would like to overload based on the number of arguments : 1 arg -> method for 1 arg, 2 args -> method for 2 args. BUT : I would also like that >2 args -> method for 2 args + va args, since the two overloads for my macro can have an arg list after the their mandatory parameters. This causes me a problem, because when i call my method with > 2 args, then the 3rd argument is used as the method name, which is wrong. – Virus721 Sep 07 '15 at 08:03
  • The solution i can think of is to hardcode a maximum number of arguments in the macro that returns the actual macro name (i.e GET_MACRO() in the linked question). This would be done by redirecting to the overload with 2 args until say 32 args. But that seems a little dirty. Would you have an idea on how to handle that more clearly ? Though don't waste your time if it doesn't come to mind easily. Thanks. – Virus721 Sep 07 '15 at 08:03
  • Macros cannot be overloaded, and they cannot count their arguments, whether variadic or not. You can probably do what you describe with just two macros, one for the 1-arg special case, and the other for 2 or more arguments. That latter would have the form `MACRO2(arg1, ...)` because the `...` must always correspond to at least one actual argument. – John Bollinger Sep 07 '15 at 14:09