如何解决“必须为可变参数宏的‘...’参数指定至少一个参数”

Ric*_*ard 7 c++ clang c-preprocessor

您可以在 C++ 中定义可变参数宏,如下所示:

#define FOO(x, ...) bar(x, __VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

但是调用FOOasFOO(1)会导致宏扩展bar(1,),这显然是一个语法错误并且无法编译。

因此 GCC 包含一个 GNU 扩展:

#define FOO(x, ...) bar(x, ##__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

这会将给定的示例扩展到所需的结果bar(1)。虽然__VA_ARGS__它是一个 GNU 扩展,但它也受到 clang 的支持,但它会在以下位置发出警告-pedantic flag

警告:“,”和 __VA_ARGS__ 的标记粘贴是 GNU 扩展 [-Wgnu-zero-variadic-macro-arguments]。

因此,C++20 包含一种新机制,以符合标准的方式实现所需结果:

#define FOO(x, ...) bar(x __VA_OPT__(,) __VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

,仅当以下内容不为空时才会添加__VA_ARGS__,否则将省略,. 这个新扩展目前适用于 GCC 和 clang trunk(启用该-std=c++2a标志): https: //godbolt.org/z/k2nAE6

我唯一的问题是 clang 在以下位置发出警告-pedantic

警告:必须为可变参数宏的“...”参数指定至少一个参数 [-Wgnu-zero-variadic-macro-arguments](GCC 不会发出警告)。

但为什么?__VA_ARGS__只有当有人只使用宏并且不向宏传递任何参数时,这似乎才有意义。但通过新的扩展,__VA_OPT__我明确地处理没有给出参数的情况。

那么为什么 clang 在这种情况下会发出警告,我该如何解决它呢?

N. *_*ead 2

这在 C++20 中已经是合法的;看来 Clang 还没有更新他们的警告。

C++20 标准(来自 N4868)在[cpp.replace.general]/5中表示:

如果宏定义中的标识符列表不以省略号结尾 [...] 否则,调用中的参数至少应与宏定义中的参数一样多...(不包括)。应存在)终止调用的预处理令牌。

将粗体部分与 C++17 的[cpp.replace]/4(来自 N4659)中的等效语句进行比较:

如果宏定义中的标识符列表不以省略号结尾 [...] 否则,调用中的参数数量应多于...宏定义中的参数数量(不包括)。应存在)终止调用的预处理令牌。

C++20 的[cpp.replace.general]/15和 C++17 的[cpp.replace]/12之间也有类似的比较。

也就是说,C++17 要求FOO(x, ...)传递至少两个参数;C++20 已将这一点削弱为仅需要一个。Clang's-pedantic似乎还没有跟上。