正如我们所知,在大多数情况下,T&&
表示"这是一个临时对象"。但是,如果想要从函数返回临时对象,他/她可以按如下方式声明函数:
template<class T>
T f()
{
T t;
......
return t;
}
或(注意:不正确)
template<class T>
T&& f()
{
T t;
......
return t;
}
但我认为后者是过度的,因为前者足够向后兼容。
然而,我还发现std::forward()
的返回类型被声明为T&amp;&amp;,所以我确信我对此的理解不完整。
我真正的问题是:我们何时何地将函数的返回类型声明为T&amp;&amp;?
答案 0 :(得分:13)
在您的示例中,T&&
是错误的,这是一个悬空参考。
但是std::forward
不会在自己的定义中返回对局部变量的右值引用,它会返回对其by-rvalue-reference参数的rvalue引用(或者对by-lvalue-reference的左值引用)参数)。
只有当您希望函数的调用者能够从引用引用的任何内容移动时,才应返回右值引用。
通常情况下,只有当函数的目的是提供对某个重要对象(可能已经存在)的移动访问时。因此,包括std::move
(允许您从左值移动),类似地,您可以编写专门为用户设计的访问器函数,以从某个对象的数据成员或某个容器的元素移动。如果对象本身不重要,只有值,则可以按值返回。
正如格雷格里所说,有时由于引用崩溃,你可以利用伎俩,这意味着你在代码中输入 T&&
,但T
已经是左值-reference类型T&&
是相同的左值引用类型。 std::forward
使用了这个技巧。也就是说,由于引用折叠T&&
并不意味着“对于T的右值引用”,它意味着“如果T是引用类型则为T,否则为对R的引用”。
答案 1 :(得分:4)
T&&
并不一定意味着结果是右值。与模板参数一起使用时,&&
表示通用引用,可以是右值或左值引用。更具体地说:如果T
是左值引用类型foo&
,则T&&
实际上是对foo
的左值引用,否则它表示右值引用。
这可以用来编写函数,它们可以采用任何类型的参数:
template<typename T> void foo(T&&);
bar a;
const bar b;
foo(a);//T and T&& will both be bar&
foo(b);//T and T&& will both be const bar&
foo(bar());//T will be bar, T&& will be bar&&
考虑到这一点std::forward
使用T&
进行调用并将其强制转换为T&&
,其中T
已明确说明。因此,如果原始函数参数是左值引用,它将返回一个,否则它将返回一个右值引用,从而实现完美转发。
关于何时将其用作返回类型:很少,尽管在传递参数时避免复制可能很有用,例如:
template<typename T> T&& foo(T&& bar) {/*some ops*/ return std::forward<T>(bar);}
答案 2 :(得分:2)
答案取决于您的功能是否是模板功能。在你的问题中,我们首先看看它是不是:
<强>非模板强>
T&&
作为返回类型并非毫无意义。原因是它实际上并不代表“临时对象”。它的意思是“右值参考”。差异很微妙,但可以使用一类与此返回类型相关的函数突出显示。也就是说,如果我们想要将引用返回到rvalue,但它引用的对象不是我们函数的本地对象,该怎么办?
T&& return_rvalue(/*some data*/)
{
T&& t = Get_a_reference();
// Do something fascinating.
return static_cast<T&&>(t);
}
此模式的一个非常特殊的情况是函数std::move
,它接受任何引用并返回相应的右值引用。当然,在实际代码中,您当然应该使用std::move
而不是直接执行演员表,因为这更清楚地表明了您的意图。
<强>模板强>
如果T
是模板参数,则T&&
是Scott Meyers所称的Universal Reference。这意味着T&&
的类型将使用引用折叠来计算...简而言之,如果T&&
我不是引用类型,则意味着T
是一个右值,如果不是引用类型,则意味着左值引用它是......