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<>从返回一个投x来T&&?
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&&.