为什么static_cast< object&&>此功能需要吗?
试图理解std ::移动
,我找到了这个答案向另一个问题。
说我有这个函数
Object&& move(Object&& arg)
{
return static_cast<Object&&>(arg);
}
我认为我理解的内容:
arg
是一个lvalue( value category )。arg
是 类型 “ rvalue ref to object”。static_cast
转换 types 。arg
和返回类型均为 类型 “ rvalue ref to object”,static_cast
是不必要的。
但是,链接的答案说:
现在,您可能想知道:我们甚至需要演员吗?答案是:是的,我们愿意。原因很简单;命名rvalue参考被视为lvalue(标准禁止使用lvalue到rvalue参考的隐式转换)。
考虑到我上面说的话,我仍然不明白为什么需要静止。
Trying to understand std::move
, I found this answer to another question.
Say I have this function
Object&& move(Object&& arg)
{
return static_cast<Object&&>(arg);
}
What I think I understand:
arg
is an lvalue (value category).arg
is of type "rvalue ref to Object".static_cast
converts types.arg
and the return type both being of type "rvalue ref to Object", thestatic_cast
is unnecessary.
However, the linked answer says:
Now, you might wonder: do we even need the cast? The answer is: yes, we do. The reason is simple; named rvalue reference is treated as lvalue (and implicit conversion from lvalue to rvalue reference is forbidden by standard).
I still don't understand why the static_cast is necessary given what I said above.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
似乎是如此,但是有必要。您可以通过尝试在没有演员的情况下编写此类功能来轻松找出答案,因为编译器应该告诉您该程序的形成不佳。该函数(模板)返回RVALUE参考。该rvalue参考不能绑定到lvalue。 id-expression
arg
是一个lvalue(如您所述),因此返回的rvalue参考不能绑定到它。在退货价值上下文之外,可能会更容易理解。规则在这里相同:
It may seem so, but it is necessary. You can find out easily by attempting to write such function without the cast, as the compiler should tell you that the program is ill-formed. The function (template) returns an rvalue reference. That rvalue reference cannot be bound to an lvalue. The id-expression
arg
is an lvalue (as you stated) and hence the returned rvalue reference cannot be bound to it.It might be easier to understand outside of return value context. The rules are same here:
我有以下心理模型(让我们使用
int
,而不是对象
)。具有名称的物体是“坐在地上”。他们是LVALUE;您不能将它们转换为rvalue参考。
进行计算时,您会从地面上选择对象,将您的东西在空中进行,然后将结果放回原处。
这些临时结果可以转换为rvalue参考。但是,一旦您“将它们放在地上”,它们就会像LVALUE一样。
我敢肯定,这仅在简单的情况下有助于,但至少它与C ++的工作方式有一些现实的类比。
I have the following mental model for it (let's use
int
instead ofObject
).Objects which have a name are "sitting on the ground". They are lvalues; you cannot convert them to rvalue references.
When you do calculations, you pick objects from the ground, do your stuff in mid-air and put the result back.
These temporary results can be converted to rvalue references. But as soon as you "put them onto the ground", they behave as lvalues.
I am sure it only helps in simple situations, but at least it gives some real-world analogy to how C++ works.
从根本上讲,您的第一个子弹是不正确的,
arg
不是lvalue,也不是rvalue。它都不是rvalue或lvalue参考,因为std ::移动
是模板。在模板上下文中,类型t&amp;&amp;
的函数参数是转发参考,如果t
是模板 - 参数。转发参考成为适当的类型,具体取决于t。因此,需要演员。以下代码不正确,因为您无法调用
foo(v)
,因为v
是一个命名对象,并且可以是一个lvalue:但是如果
foo( )
是一个模板,它可以通过int&amp;
,const int&amp;
和int&amp;&amp;&amp;
参数变为函数。您将能够调用
foo(v+5)
,其中参数是临时的,可以绑定到rvalue参考。foo
将更改函数调用后停止存在的临时对象。这是移动构造函数通常必须执行的确切动作 - 在调用其破坏者之前修改临时对象。nb:rvalue参数将在使用后或在函数呼叫结束后较早地存在。
转发引用是一种特殊的参考语法,旨在保留函数参数的值类别。 IE非模板函数
不等于
std :: Move
for对象
,它声明了类似(C ++ 11):在非template函数
arg中
是一个LVALUE,在模板中,它具有与初始化它的表达式相同的值类别。在模板中std :: remove_reference&lt; t&gt; :: type
是指t,sostd :: remove_reference&lt; t&gt; :: type&amp;&amp;&amp;&amp;&amp;&amp;
是一个真正的rvalue参考t-一种解决t&amp;&amp;
替代含义的方法。类似于上面的函数调用,如果可以隐式转换,则可以在副本构造函数合适但缺失的情况下调用移动构造函数,即错误。
返回static_cast&lt; object&amp&amp;&gt;(arg);
导致涉及呼叫的初始化涉及object :: object :: object(object&amp;&amp;&amp;&amp;&amp;)
根据的定义
,<代码>返回arg 将调用object :: Object(const Object&amp;)
。Template
std :: Move
是static_cast
type-correct“包装器”,以促进“隐式”铸件,以简化代码,以删除重复static_cast
使用代码的显式类型。Your first bullet is incorrect fundamentally,
arg
is not a lvalue, neither it is an rvalue. Neither it's a rvalue or lvalue reference, becausestd::move
is a template. In template context a function argument of typeT&&
is a forwarding reference, ifT
is a template-parameter. Forwarding reference becomes of type which appropriate, depending on what is T.A cast is required literally because of that. Following code is incorrect, because you can't call
foo(v)
, asv
is a named object and it can be an lvalue:But if
foo()
is a template, it may become a function withint&
,const int&
andint&&
arguments.You would be able to call
foo(v+5)
, where argument is a temporary, which can be bound to rvalue reference.foo
will change the temporary object which stops to exist after function call. That's the exact action which move constructors usually have to do - to modify temporary object before its destructor is called.NB: An rvalue argument would cease to exist earlier , either after its use or at end of function call.
Forwarding references are a special kind of reference syntax designed to preserve the value category of a function argument. I.e. non-template function
is not equal to
std::move
forObject
, which declared something like (c++11):In non-template function
arg
is an lvalue, in template it have same value category as expression used to initialize it. In templatestd::remove_reference<T>::type
refers to T, sostd::remove_reference<T>::type&&
is a true rvalue reference to T - a way aroundT&&
alternative meaning.By analogy to function call above, if implicit conversion was possible, then it would be possible to call move constructor where copy constructor is appropriate but missing, i.e. by mistake.
return static_cast<Object&&>(arg);
results in initialization involving call toObject::Object(Object&&)
by definition ofreturn
,return arg
would callObject::Object(const Object&)
.Template
std::move
is type-correct "wrapper" around thestatic_cast
to facilitate "implicit" cast, to simplify code by removing repeatedstatic_cast
with explicit type from code.