为什么std :: forward返回static_cast <T &&>而不是static_cast <T>?

ged*_*ial 15 c++ rvalue static-cast c++11 forwarding-reference

让我们有一个名为Y的函数重载:

void Y(int& lvalue)
{ cout << "lvalue!" << endl; }

void Y(int&& rvalue)
{ cout << "rvalue!" << endl; }
Run Code Online (Sandbox Code Playgroud)

现在,让我们定义一个像std :: forward一样的模板函数

template<class T>
void f(T&& x)
{
   Y( static_cast<T&&>(x) );   // Using static_cast<T&&>(x) like in std::forward
}
Run Code Online (Sandbox Code Playgroud)

现在看看main()

int main()
{
   int i = 10;

   f(i);       // lvalue >> T = int&
   f(10);      // rvalue >> T = int&&
}
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,输出是

lvalue!
rvalue!
Run Code Online (Sandbox Code Playgroud)

现在回到模板功能f()并替换static_cast<T&&>(x)static_cast<T>(x).让我们看看输出:

lvalue!
rvalue!
Run Code Online (Sandbox Code Playgroud)

一样的!为什么?如果它们是相同的,那么为什么std::forward<>从返回一个投xT&&

Bar*_*rry 23

左值与左值分类保持不变,但效果完全不同(值类别确实会发生变化 - 尽管在您的示例中不是以可观察的方式).让我们回顾一下这四种情况:

template<class T>
void f(T&& x)
{
    Y(static_cast<T&&>(x));
}

template<class T>
void g(T&& x)
{
    Y(static_cast<T>(x));
}
Run Code Online (Sandbox Code Playgroud)

如果我们f用左值调用,将推T导出一些X&,所以演员引用崩溃X& && ==> X&,所以我们最终得到相同的左值并且没有任何变化.

如果我们f使用rvalue进行调用,将推T导出一些,X因此转换只是转换x为rvalue引用x,因此它变为rvalue(特别是xvalue).

如果我们g用左值调用,所有相同的事情都会发生.没有必要参考折叠,因为我们只是使用T == X&,但演员仍然是一个无操作,我们仍然最终得到相同的左值.

但是如果我们g用右值调用,我们static_cast<T>(x)复制它 x.该副本一个右值(当你的测试验证时 - 除了现在它是一个prvalue而不是一个xvalue),但它最多是一个额外的,不必要的副本,并且T在最坏情况下是编译失败(如果是可移动但不可复制的).有了static_cast<T&&>(x),我们正在转换为引用,它不会调用副本.

这就是我们这样做的原因T&&.

  • @gedamial:它还能做什么?当您将`T1`转换为`T2`时,数据将被复制(通过转换)到新对象.这只能通过引用类型来避免....([或者,对于`typeid(T1)== typeid(T2)`,通过在其荒谬的默认非兼容模式下使用Visual Studio](http:// stackoverflow. COM /一个/五十六万○六百四十八分之三千七百九十六万九千三)). (2认同)
  • @gedamial`static_cast <T>(e)`相当于`T t(e);`现在你明白为什么它是副本? (2认同)
  • @gedamial"......如果`x`的类型是`T &&` ...那么......```和`x`是不一样的!?" 正确; `T &&`与`T`不同,因为一个是引用,另一个是值."`static_cast <int>(int &&)`就像是说'X && x; X t(x);`...'是的,因为`static_cast <T>`创建一个类型为`T`的值,因为Lightness是第一个注释,这里`T`不是引用类型,因此创建(复制)实际的`int`. (2认同)