I'm trying to create some trace macros that use variadic arguments. The macros only seem to function correctly when a named argument precedes the variadic ones.
A minimal code version of what I'm doing is shown below. Only TraceTest() without arguments fails. I have also tried to create an intermediate macro that passes a dummy first argument to TraceTest1, but that fails too.
template<typename ...Args>
inline void f(const char*, Args&&... args) { }
#define TraceTest1(a, args...) f("Trace Start ", ##args)
#define TraceTest(args...) f("Trace Start", ##args)
TraceTest(); // error: expected primary-expression before ‘)’ token
TraceTest("a"); // works
TraceTest1(); // works
TraceTest1("a"); // works
I have read the gnu docs on variadic macros but could find nothing that would explain this.
I am using gcc 7.4.0 under Ubuntu 18.04 and compiling with
g++ -Wall -Wextra -std=c++17 src/event.cpp -obin/event
TraceTest()
expands to f("Trace start",)
, which is obviously a syntax error.
Both named variadic macro parameters and token pasting of ',' and variadic macro parameters are not standard C++ (even though every compiler I can find implements the latter). If you want them with GCC, use "-std=gnu++17" instead of "-std=c++17".
Note that C++20 is adding a new __VA_OPT__
preprocessor token that can be used to do this in a portable way:
#define TraceTest(...) f("Trace Start " __VA_OPT__(,) __VA_ARGS__)
__VA_OPT__
is replaced with its parameters only if __VA_ARGS__
isn't empty, so TraceTest()
will be replaced with f("Trace Start ")
.