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

时间:2016-07-07 17:23:46

标签: c++ c++11 rvalue static-cast forwarding-reference

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

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

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

现在,让我们定义一个模板函数,其作用类似于std :: forward

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

现在看看main()

int main()
{
   int i = 10;

   f(i);       // lvalue >> T = int&
   f(10);      // rvalue >> T = int&&
}

正如预期的那样,输出是

lvalue!
rvalue!

现在返回模板函数f()并将static_cast<T&&>(x)替换为static_cast<T>(x)。让我们看看输出:

lvalue!
rvalue!

它是一样的!为什么?如果它们相同,那么为什么std::forward<>会将演员从x返回到T&&

1 个答案:

答案 0 :(得分: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));
}

如果我们使用左值调用fT将推导为X&,因此投射参考会折叠X& && ==> X&,因此我们最终得到相同的左值没有什么变化。

如果我们使用左值调用f,则T会推断为某些X,因此演员只会将x转换为对x的右值引用,所以它变成了一个rvalue(特别是一个xvalue)。

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

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

这就是为什么我们T&&