简体   繁体   English

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

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

Let's have a function called Y that overloads: 让我们有一个名为Y的函数重载:

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

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

Now, let's define a template function that acts like std::forward 现在,让我们定义一个像std :: forward一样的模板函数

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

Now look at the main() 现在看看main()

int main()
{
   int i = 10;

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

As expected, the output is 正如预期的那样,输出是

lvalue!
rvalue!

Now come back to the template function f() and replace static_cast<T&&>(x) with static_cast<T>(x) . 现在回到模板函数f()并用static_cast<T&&>(x)替换static_cast<T&&>(x) static_cast<T>(x) Let's see the output: 让我们看看输出:

lvalue!
rvalue!

It's the same! 一样的! Why? 为什么? If they are the same, then why std::forward<> returns a cast from x to T&& ? 如果它们是相同的,那么为什么std::forward<>会将一个转换从x返回到T&&

The lvalue vs rvalue classification remains the same, but the effect is quite different (and the value category does change - although not in an observable way in your example). 左值与左值分类保持不变,但效果完全不同(值类别确实会发生变化 - 尽管在您的示例中不是以可观察的方式)。 Let's go over the four cases: 让我们回顾一下这四种情况:

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

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

If we call f with an lvalue, T will deduce as some X& , so the cast reference collapses X& && ==> X& , so we end up with the same lvalue and nothing changes. 如果我们用左值调用fT将推导出一些X& ,因此强制转换引用会折叠X& && ==> X& ,因此我们最终得到相同的左值并且没有任何变化。

If we call f with an rvalue, T will deduce as some X so the cast just converts x to an rvalue reference to x , so it becomes an rvalue (specifically, an xvalue). 如果我们调用f与右值, T将演绎一些X所以剧组只是转换x到一个右值参考x ,因此它成为一个右值(具体地说,x值)。

If we call g with an lvalue, all the same things happen. 如果我们用左值调用g ,那么所有相同的事情都会发生。 There's no reference collapsing necessary, since we're just using T == X& , but the cast is still a no-op and we still end up with the same lvalue. 没有必要参考折叠,因为我们只是使用T == X& ,但是演员仍然是无操作,我们仍然以相同的左值结束。

But if we call g with an rvalue, we have static_cast<T>(x) which will copy x . 但是如果我们使用rvalue调用g ,我们有static_cast<T>(x)复制 x That copy is an rvalue (as your test verifies - except now it's a prvalue instead of an xvalue), but it's an extra, unnecessary copy at best and would be a compilation failure (if T is movable but noncopyable) at worst. 该副本一个右值(当你的测试验证时 - 除了现在它是一个prvalue而不是一个xvalue),但它最多是一个额外的,不必要的副本,并且在最坏的情况下是编译失败(如果T是可移动但不可复制的)。 With static_cast<T&&>(x) , we were casting to a reference, which doesn't invoke a copy. 使用static_cast<T&&>(x) ,我们正在转换为引用,该引用不会调用副本。

So that's why we do T&& . 这就是我们做T&&的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM