gpt4 book ai didi

c++ - 即使使用 ##__VA_ARGS__ 也无法编译具有零参数的可变参数宏

转载 作者:行者123 更新时间:2023-12-01 14:38:49 26 4
gpt4 key购买 nike

如果我尝试编译以下代码:

template <typename... TArgs>
void Dummy(const TArgs &...args)
{
}

#define DUMMY(...) Dummy("Hello", ##__VA_ARGS__)

int main()
{
DUMMY();
}

我得到以下编译错误:

g++ -std=c++17 -O3 -Wall main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:6:48: error: expected primary-expression before ')' token
6 | #define DUMMY(...) Dummy("Hello", ##__VA_ARGS__)
| ^
main.cpp:10:5: note: in expansion of macro 'DUMMY'
10 | DUMMY();
| ^~~~~

https://coliru.stacked-crooked.com/a/c9217ba86e7d24bd

当我至少添加一个参数时,代码可以正常编译:

template <typename... TArgs>
void Dummy(const TArgs &...args)
{
}

#define DUMMY(dummy, ...) Dummy(dummy, ##__VA_ARGS__)

int main()
{
DUMMY(); // This is strange. Why does this compile?
DUMMY(1);
DUMMY(1, 2);
DUMMY(1, 2, 3);
}

https://coliru.stacked-crooked.com/a/e30e14810d70f482

但我不确定它是否正确,因为 DUMMY 至少需要一个参数,但我传递了零。

最佳答案

关于 C/C++ 宏的一个重要事实是,不带参数调用它们是不可能的,因为宏参数允许是空标记序列。

因此,DUMMY() 使用单个空参数而不是零参数调用宏 DUMMY。这解释了为什么第二个示例有效,也解释了为什么第一个示例产生语法错误。

__VA_ARGS__ 没有元素时,GCC 扩展从 , ##__VA_ARGS__ 中删除逗号。但是一个空参数与没有参数是不一样的。当您将 DUMMY 定义为 #define DUMMY(...) 时,您保证 __VA_ARGS__ 至少有一个参数,因此 , 不会被删除。

***注意:如果您没有使用 --std 选项指定某些 ISO 标准,GCC 会对该规则做出异常(exception)处理。在这种情况下,如果 ... 是唯一的宏参数并且调用有一个空参数,那么 ,##__VA_ARGS__ 确实 删除了逗号。这在 CPP manual in the Variadic Marcos section 中有说明。 :

The above explanation is ambiguous about the case where the only macro parameter is a variable arguments parameter, as it is meaningless to try to distinguish whether no argument at all is an empty argument or a missing argument. CPP retains the comma when conforming to a specific C standard. Otherwise the comma is dropped as an extension to the standard.

DUMMY#define DUMMY(x, ...) 时,如果 DUMMY __VA_ARGS 将为空> 仅使用一个参数调用,其中包括调用 DUMMY()(一个空参数)和 DUMMY(0)(一个参数,0)。请注意,C++20 之前的标准 C 和 C++ 不允许此调用;他们要求至少有一个(可能为空的)参数对应于省略号。不过,GCC 从未施加此限制,并且无论 --std 设置如何,GCC 都会忽略 ,##__VA_ARGS__ 的逗号。

从 C++20 开始,您可以使用 __VA_OPT__ 内置宏作为处理逗号(以及任何其他可能需要删除的标点符号)的更标准方式。 __VA_OPT__ 也避免了上面出现的空参数问题,因为它使用了不同的标准:__VA_OPT__(x) 扩展为 x if __VA_ARGS__ 包含至少一个标记;否则,它扩展为一个空序列。因此,对于这个问题中的宏,__VA_OPT__ 将按预期工作。

我相信所有主要编译器现在都实现了 __VA_OPT__,至少在它们的最新版本中是这样。

关于c++ - 即使使用 ##__VA_ARGS__ 也无法编译具有零参数的可变参数宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63740056/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com