将函数的返回类型声明为T&&amp ;?是没有意义的。

时间:2013-01-30 13:42:48

标签: c++ c++11 return-type rvalue-reference temporary

正如我们所知,在大多数情况下,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;?

3 个答案:

答案 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是一个右值,如果不是引用类型,则意味着左值引用它是......