为什么可变参数宏会在“)”标记之前以预期的主表达式而失败,除非前面带有命名参数?

时间:2019-05-30 01:10:16

标签: c++ macros g++ variadic-macros

我正在尝试创建一些使用可变参数的跟踪宏。仅当命名参数位于可变参数之前,这些宏才能正常运行。

下面显示了我正在做的最小代码版本。只有不带参数的TraceTest()失败。我还尝试创建一个中间宏,该宏将一个虚拟的第一个参数传递给TraceTest1,但是也失败了。

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

我已经阅读了有关可变参数宏的gnu文档,但找不到任何可以解释这一点的东西。

我正在Ubuntu 18.04下使用gcc 7.4.0并使用

进行编译
g++ -Wall -Wextra -std=c++17 src/event.cpp -obin/event

1 个答案:

答案 0 :(得分:1)

TraceTest()扩展为f("Trace start",),这显然是语法错误。

命名的可变参数宏参数和令牌标记','和可变参数宏参数都不是标准的C ++(即使我能找到的每个编译器都实现了后者)。如果您希望将它们与GCC一起使用,请使用“ -std = gnu ++ 17”而不是“ -std = c ++ 17”。


请注意,C ++ 20正在添加一个新的__VA_OPT__预处理器令牌,该令牌可用于移植:

#define TraceTest(...) f("Trace Start " __VA_OPT__(,) __VA_ARGS__)

Live Demo

__VA_OPT__仅在__VA_ARGS__不为空时被其参数替换,因此TraceTest()将被f("Trace Start ")替换。