我见过多个代码实例,其中函数参数包使用&&符号,如下所示,但我看不出使用这种表示法有什么好处。
return [
{
label: '"lodash"',
kind: monaco.languages.CompletionItemKind.Function,
documentation: "The Lodash library exported as Node.js modules.",
insertText: '"lodash": "*"',
sortText: 'a'
},
{
label: '"express"',
kind: monaco.languages.CompletionItemKind.Function,
documentation: "Fast, unopinionated, minimalist web framework",
insertText: '"express": "*"',
sortText: 'b'
},
{
label: '"mkdirp"',
kind: monaco.languages.CompletionItemKind.Function,
documentation: "Recursively mkdir, like <code>mkdir -p</code>",
insertText: '"mkdirp": "*"',
sortText: 'c'
}
];
我的第一个想法是&amp;&amp; form将专门用于r值对象,但是这个测试证明了错误:
template<typename... Args>
void Function(Args... args)
{
}
template<typename... Args>
void Function(Args&&... args)
{
}
在这里,VS 2017抱怨该功能的两种形式都是可行的候选人。
有人可以解释这两者之间的区别,以及对另一方有什么好处?
答案 0 :(得分:2)
它们是参数包表单中的转发引用。对于模板参数推导,它们可以匹配任何参数,但模板参数将与普通模板参数相比推导出不同。
转发引用的主要优点是,如果与std::forward
一起使用,将保留左值/右值信息。因此,它们被用来“转发”某些东西。
例如,
void real_foo(A const &a);
void real_foo(A &&a);
template<class... Args>
void foo_proxy_ordinary(Args... args) { real_foo(args...); }
template<class... Args>
void foo_proxy_perfect(Args&&... args) { real_foo(std::forward<Args>(args)...); }
普通版本将始终调用real_foo(A const &)
版本,因为在foo_proxy
内,args
始终是左值。
但是,如果传入的参数确实是rvalues,完美版本将选择real_foo(A&&)
。
将转发引用与参数包相结合,可以轻松编写通用代理函数,而不会在lvalue / rvalue方面造成性能损失。
答案 1 :(得分:2)
T&&
在
template<typename T>
void f(T&& t);
称为 转发参考 ,有时也称为 通用参考 。
转发参考的主要优势与std::forward
相结合,可实现所谓的 完美转发 :功能模板将其参数传递给另一个函数(左值为左值,右值为右值)。
现在可以创建 高阶函数 ,将其他函数作为参数或返回它们,或者更高级的函数包装器(例如std::make_shared
),并做其他很酷的事情。
以下是一些材料,它比我可能更好,更详细地解释它:
答案 2 :(得分:1)
有人可以解释这两者之间的区别,以及对另一方有什么好处?
参数包的差异与单个参数的差异相同。 Args
声明一个“对象参数”(按值传递),Args&&
声明一个引用参数(通过引用传递)。
通过引用传递允许人们避免在不需要时复制参数。如果引用是非const的,它还允许修改引用的参数,包括从该对象移动的可能性。
按值传递使调用者明白传递的对象既不会被修改,也不会被称为调用函数的结果。
我的第一个想法是&amp;&amp;表单将专门用于r值对象
正如您的测试所示,这确实是一个不正确的假设。当Args
是推导类型,即auto
或模板参数时,Args&&
确实可以是l值引用或r值引用。它取决于Args
被推导出来的内容。这简洁地演示了参考折叠规则:
typedef int& lref;
typedef int&& rref;
int n;
lref& r1 = n; // type of r1 is int&
lref&& r2 = n; // type of r2 is int& note this case in particular
rref& r3 = n; // type of r3 is int&
rref&& r4 = 1; // type of r4 is int&&
使用这样的引用允许转发,即重新绑定到新的左值引用(如果可能)或从对象移动(如果可能)或复制(当前者都不可能时)。
因此,当Args&&
是推断类型时,Args
被称为转发引用(或通用引用)。