Weird behavior of variadic macro expansion with gcc and clang

Viewed 536

I'm writing a variadic dispatcher macro in C++, to call a different macro based on the number of arguments (from none up to 5) provided to the dispatcher. I came up with this solution:

#define GETOVERRIDE(_ignored, _1, _2, _3, _4, _5, NAME, ...) NAME
#define NAMEDARGS(...) GETOVERRIDE(ignored, ##__VA_ARGS__, NAMEDARGS5, NAMEDARGS4, NAMEDARGS3, NAMEDARGS2, NAMEDARGS1, NAMEDARGS0)(__VA_ARGS__)

NAMEDARGS is the dispatcher macro; calling it with 1 argument will result in a call to NAMEDARGS1 which takes 1 argument, and so on (I don't provide the implementations of the various NAMEDARGS# since they are irrelevant in this context).

I tested the code gcc 7.1.1, and I found a weird behavior of the gcc expansion when using the -std=c++14 flag. With this test code:

NAMEDARGS()
NAMEDARGS(int)
NAMEDARGS(int, float)

I get these expansions:

$ gcc -E testMacro.cpp
NAMEDARGS0()
NAMEDARGS1(int)
NAMEDARGS2(int, float)

$ gcc -E -std=c++14 testMacro.cpp
NAMEDARGS1()
NAMEDARGS1(int)
NAMEDARGS2(int, float)

It seems that using the -std=c++14 flag the substitution of the zero-argument call fails, resulting in the call of the one-argument macro. I thought that this could be because the ##__VA_ARGS__ syntax is a GNU extension, thus not working with an ISO C++ preprocessor; however, when trying with clang 4.0.1 I obtain the desired expansion:

$ clang -E -std=c++14 testMacro.cpp
NAMEDARGS0()
NAMEDARGS1(int)
NAMEDARGS2(int, float)

So I don't understand what's going on here. Does clang implement this gnu extension, accepting non-ISO code also with -std==c++14 unlike gcc? Or maybe the problem lies elsewhere? Thanks for the help.

1 Answers
Related