可变模板参数包转发中的语法差异

Syntax differences in variadic template parameter pack forwarding

在使用可变参数模板时,我遇到了两种不同的方式来编写对 std::forward 的调用,但我想知道这两种语法之间的实际区别是什么?

template<typename... T>
void one(T&&... args)
{
    foo(std::forward<T&&...>(args...));
}
template<typename... T>
void two(T&&... args)
{
    foo(std::forward<T&&>(args)...);
}

根据我的编译器,这些都是有效的语法,并且在大多数情况下,编译器不会报错。但是我发现了一些情况,其中一个或另一个是正确的,但编译器没有详细说明原因。

一个比另一个更正确吗?
它们有不同的用途吗?

... 位置告诉编译器在哪里扩展包,对它之前的每个元素一次(很难简单地表达,但我将在下面说明)。

让我们考虑一包 T = {int, double, char}args = {1, 2.0, '3'}

您的第一个示例 (one) 将在 <> 内扩展 T,然后在 () 内扩展 args,因此它变为

foo(std::forward<T&&...>(args...));  // becomes:
foo(std::forward<int&&, double&&, char&&>(1, 2.0, '3'));

这不是 std::forward 的工作方式,因为它只需要一个参数。您的第二个示例 (two) 表示为包中的每个项目扩展对 std::forward 的整个调用一次,因此它变为

foo(std::forward<T&&>(args)...);  // becomes:
foo(std::forward<int&&>(1), std::forward<double&&>(2.0),std::forward<char&&>('3'));

至于为什么这两个编译都很好,如果你只用一个参数调用,结果是相同的。如果您根本没有调用它,那么它就不会被实例化。