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

Why does variadic macro fail with expected primary-expression before ‘)’ token unless preceded by a named argument?


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

Solution

  • 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__)
    

    Live Demo

    __VA_OPT__ is replaced with its parameters only if __VA_ARGS__ isn't empty, so TraceTest() will be replaced with f("Trace Start ").