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

Why does std::forward return static_cast<T&&> and not static_cast<T>?

本文关键字:lt gt cast static 为什么 forward 返回 std      更新时间:2023-10-16

让我们有一个名为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&&

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

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&折叠,所以我们最终得到相同的左值,没有任何变化。

如果我们用右值调用fT会推断为某种X所以强制转换只是将x转换为右值引用x,所以它变成了右值(特别是x值)。

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

但是,如果我们用右值调用g,我们将static_cast<T>(x)复制x .该副本是一个右值(正如您的测试所验证的那样 - 除了现在它是一个 prvalue 而不是 xvalue),但它充其量是一个额外的、不必要的副本,并且在最坏的情况下将是编译失败(如果T是可移动但不可复制的)。对于 static_cast<T&&>(x) ,我们强制转换为不调用副本的引用。

所以这就是为什么我们做T&&.