例如
template <typename T>
void function(T&& arg)
有人可以详细解释一下函数签名是如何结束左值的 T& 和传入的右值的 T&& 的吗?我知道以某种方式(需要标准行) T -> T& 在左值的情况下和 T -> T 在重值的情况下,然后通过组合 & 和 && 它产生左值/右值引用。
该规则可在第 8.3.2p6 节中找到。
如果 typedef 、 type template-parameter或decltype-specifier表示的类型
TR
是对 type 的引用T
,则尝试创建类型“lvalue reference to cvTR
”会创建类型“lvalue reference toT
”,而尝试创建类型“lvalue reference to cv”时创建类型“对cvTR
的右值引用”创建类型TR
。
或以表格形式:
TR R
T& & -> T& // lvalue reference to cv TR -> lvalue reference to T
T& && -> T& // rvalue reference to cv TR -> TR (lvalue reference to T)
T&& & -> T& // lvalue reference to cv TR -> lvalue reference to T
T&& && -> T&& // rvalue reference to cv TR -> TR (rvalue reference to T)
这要归功于参考折叠规则。假设这U
是一个非引用类型;然后:
T = U T & = U & T && = U &&
If T = U & , then T & = U & and T && = U & .
T = U && T & = U & T && = U &&
因此,如果您的函数参数可以绑定到类型的左值引用U
,则T
必须推导出为U &
才能T &&
成为U &
,这是唯一的选择,因为左值不能绑定到右值引用。另一方面,如果您的参数是 type 的右值U
,则推导T
出为U
,并且您的参数可以绑定。T &&
U &&
关键是匹配的引用类型是T &&
(而不是T
!)。但是,由于arg
它本身是一个命名变量,因此是一个左值,因此您必须使用它std::forward<T>(arg)
来创建一个与调用您的函数的表达式相同的表达式。