Strange behavior of variational macro expansion with gcc and clang

I am writing a variable dispatcher macro in C ++ to call another macro based on the number of arguments (one to five) given 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 a dispatch macro; calling it with 1 argument will result in a call to NAMEDARGS1, which takes one argument, etc. (I do not provide implementations of the various NAMEDARGS # as they are irrelevant in this context).

I tested the gcc 7.1.1 code and I found strange behavior of the gcc extension when using the -std = C ++ 14 flag with this test code:

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

      

I get these decompositions:

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

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

      

It looks like using the -std = C ++ 14 flag, overriding a call with a null argument fails, resulting in a single-argument macro being called. I thought it might be because the C ## __ VA_ARGS__ syntax is a GNU extension, so it doesn't work with the ISO C ++ preprocessor; however when trying with clang 4.0.1 I get the desired extension:

$ 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 use this gnu extension, accepting non-ISO code also with -std == C ++ 14 as opposed to gcc? Or maybe the problem lies elsewhere? Thanks for the help.

+3


source to share


1 answer


GCC by default -std

is gnu++14

(see here ) which is C ++ 14 with GNU extensions.

Comparing the two with only NAMEDARGS(...)

shows how the expansions differ:

code

#define NAMEDARGS(...) GETOVERRIDE(ignored, ##__VA_ARGS__, NAMEDARGS5, NAMEDARGS4, NAMEDARGS3, NAMEDARGS2, NAMEDARGS1, NAMEDARGS0)(__VA_ARGS__)
NAMEDARGS()

      

-std = gnu ++ 14 -E

GETOVERRIDE(ignored, NAMEDARGS5, NAMEDARGS4, NAMEDARGS3, NAMEDARGS2, NAMEDARGS1, NAMEDARGS0)()
-------------------^

      

-std = C ++ 14 -E



GETOVERRIDE(ignored,, NAMEDARGS5, NAMEDARGS4, NAMEDARGS3, NAMEDARGS2, NAMEDARGS1, NAMEDARGS0)()
-------------------^^

      

I'm not a seasoned standard reader, but I found the following two passes in [cpp.replace] that assume GCC is correct in both calls:

If a list identifier in a macro definition does not end with an ellipsis, the number of arguments (including those that do not consist of preprocessing tokens) when calling a functionally similar macro must equal the number of parameters in the macro definition. Otherwise, the call must have more arguments than the macro definition (excluding ...). There must be a) preprocessing token that ends the call.

...

If the macro type definition contains ... immediately preceding), then trailing arguments, including any pre-processing comma delimiters, are concatenated to form one element: variable arguments. The number of arguments combined in this way is such that after the merge the number of arguments is greater than the number of parameters in the macro definition (excluding ...).

It seems correct that empty __VA_ARGS__

expands to one empty argument.

I can't seem to find if this should be clan behavior here.

+2


source







All Articles