std :: move()如何将值传递给RValues?
我发现自己不完全理解std::move()
的逻辑。
起初,我对它进行了搜索,但似乎只有关于如何使用std::move()
文档,而不是它的结构如何工作。
我的意思是,我知道模板成员函数是什么,但是当我查看VS2010中的std::move()
定义时,它仍然令人困惑。
std :: move()的定义如下。
template<class _Ty> inline
typename tr1::_Remove_reference<_Ty>::_Type&&
move(_Ty&& _Arg)
{ // forward _Arg as movable
return ((typename tr1::_Remove_reference<_Ty>::_Type&&)_Arg);
}
对我来说最奇怪的是参数(_Ty && _Arg),因为当我像下面看到的那样调用函数时,
// main()
Object obj1;
Object obj2 = std::move(obj1);
它基本上等于
// std::move()
_Ty&& _Arg = Obj1;
但是,正如你已经知道的,你不能直接将LValue链接到RValue引用,这使我认为它应该是这样的。
_Ty&& _Arg = (Object&&)obj1;
然而,这是荒谬的,因为std :: move()必须适用于所有的值。
所以我想完全理解这是如何工作的,我也应该看看这些结构。
template<class _Ty>
struct _Remove_reference
{ // remove reference
typedef _Ty _Type;
};
template<class _Ty>
struct _Remove_reference<_Ty&>
{ // remove reference
typedef _Ty _Type;
};
template<class _Ty>
struct _Remove_reference<_Ty&&>
{ // remove rvalue reference
typedef _Ty _Type;
};
不幸的是,它仍然令人困惑,我不明白。
我知道这都是因为我缺乏关于C ++的基本语法技巧。 我想知道这些工作是如何进行的,我可以在互联网上获得的任何文件都会受到欢迎。 (如果你可以解释这一点,那也会很棒)。
我们从移动功能开始(我清理了一下):
template <typename T>
typename remove_reference<T>::type&& move(T&& arg)
{
return static_cast<typename remove_reference<T>::type&&>(arg);
}
让我们从更容易的部分开始 - 也就是说,当用rvalue调用函数时:
Object a = std::move(Object());
// Object() is temporary, which is prvalue
我们的move
模板被实例化如下:
// move with [T = Object]:
remove_reference<Object>::type&& move(Object&& arg)
{
return static_cast<remove_reference<Object>::type&&>(arg);
}
由于remove_reference
将T&
T
转换为T
或将T&&
为T
,并且Object
不是引用,因此我们的最终功能是:
Object&& move(Object&& arg)
{
return static_cast<Object&&>(arg);
}
现在,你可能会想:我们是否需要演员? 答案是:是的,我们有。 原因很简单; 命名右值引用被视为左值(并且左值到右值引用的隐式转换被标准禁止)。
以下是我们使用左值调用move
时会发生的情况:
Object a; // a is lvalue
Object b = std::move(a);
和相应的move
实例化:
// move with [T = Object&]
remove_reference<Object&>::type&& move(Object& && arg)
{
return static_cast<remove_reference<Object&>::type&&>(arg);
}
再次, remove_reference
将Object&
转换为Object
,我们得到:
Object&& move(Object& && arg)
{
return static_cast<Object&&>(arg);
}
现在我们来到棘手的部分: Object& &&
甚至意味着什么?它如何绑定到左值?
为了实现完美的转发,C ++ 11标准为参考折叠提供了特殊规则,如下所示:
Object & & = Object &
Object & && = Object &
Object && & = Object &
Object && && = Object &&
正如你所看到的,在这些规则下Object& &&
实际上意味着Object&
,它是允许绑定左值的普通左值引用。
最终的功能是:
Object&& move(Object& arg)
{
return static_cast<Object&&>(arg);
}
这与以前用rvalue实例化并无不同 - 它们都将参数转换为右值引用,然后将其返回。 区别在于第一个实例化只能用于右值,而第二个实例化只能用于左值。
为了解释为什么我们需要更多的remove_reference
,我们来试试这个函数
template <typename T>
T&& wanna_be_move(T&& arg)
{
return static_cast<T&&>(arg);
}
并用左值实例化它。
// wanna_be_move [with T = Object&]
Object& && wanna_be_move(Object& && arg)
{
return static_cast<Object& &&>(arg);
}
应用上面提到的参考折叠规则,您可以看到我们获得的功能在move
不可用(简单来说,您使用左值调用它,您将返回左值)。 如果有的话,这个函数是身份函数。
Object& wanna_be_move(Object& arg)
{
return static_cast<Object&>(arg);
}
_Ty是一个模板参数,在这种情况下
Object obj1;
Object obj2 = std::move(obj1);
_Ty键入“Object&”
这就是为什么_Remove_reference是必需的。
它会更像
typedef Object& ObjectRef;
Object obj1;
ObjectRef&& obj1_ref = obj1;
Object&& obj2 = (Object&&)obj1_ref;
如果我们没有删除参考,那就好像我们正在做的那样
Object&& obj2 = (ObjectRef&&)obj1_ref;
但ObjectRef &&减少到Object&,我们无法绑定到obj2。
它减少这种方式的原因是为了支持完美的转发。 看到这篇文章。
链接地址: http://www.djcxy.com/p/73011.html