C++ 将函数的返回类型声明为T&&;?

C++ 将函数的返回类型声明为T&&;?,c++,c++11,return-type,rvalue-reference,temporary,C++,C++11,Return Type,Rvalue Reference,Temporary,正如我们所知,在大多数情况下,T&&表示“这是一个临时对象”。但是,如果要从函数返回临时对象,可以按如下方式声明函数: template<class T> T f() { T t; ...... return t; } 模板 tf() { T; ...... 返回t; } 或(注意:不正确) 模板 T&f() { T; ...... 返回t; } 但我认为后者有点过头了,因为前者已经足够了,而且向后兼容 但是,我还发现std::forward()的返回

正如我们所知,在大多数情况下,
T&&
表示“这是一个临时对象”。但是,如果要从函数返回临时对象,可以按如下方式声明函数:

template<class T>
T f()
{
    T t;
    ......

    return t;
}
模板
tf()
{
T;
......
返回t;
}
或(注意:不正确)

模板
T&f()
{
T;
......
返回t;
}
但我认为后者有点过头了,因为前者已经足够了,而且向后兼容

但是,我还发现
std::forward()
的返回类型被声明为T&&,因此我确信我对这一点的理解是不完整的


我真正的问题是:我们应该在何时何地将函数的返回类型声明为T&?

答案取决于函数是否为模板函数。在你的问题中是这样的,但让我们先看看它是否是:

非模板

T&
作为返回类型并非毫无意义。原因是,它实际上并不意味着“临时对象”。它的意思是“右值引用”。区别很细微,但可以通过与此返回类型相关的一类函数来突出显示。也就是说,如果我们想要返回一个对右值的引用,但它引用的对象不是我们函数的本地对象,该怎么办

T&& return_rvalue(/*some data*/)
{
   T&& t = Get_a_reference();
   // Do something fascinating.
   return static_cast<T&&>(t);
}
T&&return\u右值(/*某些数据*/)
{
T&&T=Get_a_reference();
//做些有趣的事。
返回静态_-cast(t);
}
此模式的一个非常特殊的情况是函数
std::move
,它接受任何引用并返回相应的右值引用。当然,在实际代码中,您当然应该使用
std::move
而不是直接执行强制转换,因为这更清楚地显示了您的意图

模板


如果
T
是一个模板参数,
T&
就是Scott Meyers所说的模板参数。这意味着
T&
的类型将使用引用折叠。。。简而言之,如果
T
i不是引用类型,则表示
T&&
是右值引用,如果是,则表示为左值引用。

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&&

在您的示例中,
T&
是错误的,它是一个悬空引用

但是
std::forward
不会在其自身定义中返回对局部变量的右值引用,而是返回对其by-rvalue引用参数的右值引用(或对by-lvalue引用参数的左值引用)

仅当您希望函数的调用方能够从该引用引用引用的任何对象移动时,才应返回右值引用

通常,只有当函数的目的是提供对某个重要对象(可能已经存在)的移动访问时,才会出现这种情况。因此,这包括
std::move
(它允许您从左值移动),类似地,您可以编写一个专门为用户设计的访问器函数,用于从某个对象的数据成员或某个容器的元素移动。如果对象本身不重要,则只返回值,然后可以按值返回


正如grizzly所说,有时由于引用崩溃,您可以利用一些技巧,这意味着您可以在代码中键入
T&
,但是当
T
已经是左值引用类型时,
T&&
是相同的左值引用类型<代码>标准::转发使用该技巧。也就是说,因为引用折叠
T&&
并不意味着“对T的右值引用”,它意味着“如果T是引用类型,则对T的右值引用”。请用一个简单的经验法则来看看这里:只允许“move”和“forward”返回
T&
。(对于挑剔的人:我在模糊的意义上使用了“move”和“forward”,其中包括来自move迭代器的
op*
)相关的:Scott Meyer's。“正如我们所知,T&&表示“这是一个临时对象”。“我们当然不知道这一点。”。但是,如果一个人想要从函数返回一个临时对象,他/她可以如下声明函数“-不,他们不能(至少是第二个版本的
&&
)<代码>&&是(或可能意味着)临时的引用。不要返回对局部变量的引用。这适用于右值引用,就像它从那以后一直适用于左值引用一样。回答得好!第一句话明确区分了两个例子之间的差异。谢谢
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&&
template<typename T> T&& foo(T&& bar) {/*some ops*/ return std::forward<T>(bar);}