Search code examples
c++cmacrosg++variadic-macros

Why won't my variadic macro accept no arguments correctly?


Overloading Macro on Number of Arguments

https://codecraft.co/2014/11/25/variadic-macros-tricks/

I've been looking at the two links above, trying to get the following code to work:

#define _GET_NUMBER(_0, _1, _2, _3, _4, _5, NAME, ...) NAME
#define OUTPUT_ARGS_COUNT(...) _GET_NUMBER(_0, ##__VA_ARGS__, 5, 4, 3, 2, 1, 0)

...

cout << OUTPUT_ARGS_COUNT("HelloWorld", 1.2) << endl;
cout << OUTPUT_ARGS_COUNT("HelloWorld") << endl;
cout << OUTPUT_ARGS_COUNT() << endl;

This compiles, runs, and gives the following output:

2
1
1

I can not for the life of me figure out why the call OUTPUT_ARGS_COUNT() is giving me 1 instead of 0. I have an ok understanding of the code I'm trying to use, but it's a tad greek to me still so I guess it's possible that I'm not applying something correctly despite the fact I literally copied and pasted the example code from the link on stack overflow.

I'm compiling using g++ 5.4.0 20160609.

Any ideas or additional resources you can point me to would be greatly appreciated.


Solution

  • The C standard specifies

    If the identifier-list in the macro definition does not end with an ellipsis, [...]. Otherwise, there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...)

    (C2011 6.10.3/4; emphasis added)

    C++11 contains language to the same effect in paragraph 16.3/4.

    In both cases, then, if your macro invocation were interpreted to have zero arguments then your program would be non-conforming. On the other hand, the preprocessor does recognize and support empty macro arguments -- that is, arguments consisting of zero preprocessing tokens. In principle, then, there is an ambiguity here between no argument and a single empty argument, but in practice, only the latter interpretation results in a conforming program.

    That g++ opts for the latter interpretation (the other answer quotes its documentation to that effect) is thus reasonable and appropriate, but it is not safe to rely upon it if you want your code to be portable. A compiler that takes the alternative interpretation would behave differently, possibly by providing the behavior you expected, but also possibly by rejecting the code.