[英]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. 如果我们用左值调用
f
, T
将推导出一些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.