我是C++参数包扩展的新手,长期以来一直对
...
(省略号)的位置感到困惑,例如:
template <typename... Args>
void func(Args&&... args) {
// ...
std::forward<Args>(args)...;
// ...
}
为什么没有
std::forward<Args>(args...)
?我应该遵守什么规则?
查看 https://en.cppreference.com/w/cpp/language/parameter_pack,特别是“包扩展”部分。
基本上,包扩展中的“...”几乎就像一个宏:在某种程度上,它创建了更多源代码。 “...”之前的内容都会为每个参数重复(并且包名称替换为所述参数),因此像
func(args...)
这样的内容将被扩展为“func(a, b, c)”,而 func(args)...
会变成“func(a), func(b), func(c)”。
std::forward
仅接受一个参数并生成一个转发项:func(std::forward(args)...)
将变成单个转发的列表:func(std::forward(a), std::forward(b), std::forward(c))
。因此,它需要一个参数列表,并生成一个转发参数列表
从语法上来说,
std::forward<Args>(args)...;
没有意义。
您只能在括号或大括号内使用包扩展。
如果你要调用一个函数,比如
foo
,那么你会写:
foo(std::forward<Args>(args)...)
这将是一个后缀表达式
foo(/* ... */)
,其中包含一个表达式列表,它是一个初始化器列表,带有单个初始化器子句std::forward<Args>(args)
和一个...
。
换句话说,
...
不是表达式的一部分;它是表达式列表的一部分。
因此, ...
是“最外层”的东西,因为它的优先级低于任何表达式。
*args...
和 args()...
将分别将 *
和 ()
应用于 args
中的每个参数。
您可以将 X...
视为一条指令:
对包中的每个元素执行
。X
std::forward<Args>(args...)
是错误的,因为这里的...
适用于调用std::forward
时参数的initializer-list,但
std::forward
不是可变参数函数模板。
它不会转发每个参数,而是尝试调用 std::forward
并传递整个包。