Move()如何将值传递到 RValue 中?

我只是发现自己没有完全理解 std::move()的逻辑。

起初,我在谷歌上搜索了它,但似乎只有关于如何使用 std::move()的文档,而没有关于它的结构如何工作的文档。

我的意思是,我知道模板成员函数是什么,但是当我查看 VS2010中的 std::move()定义时,它仍然令人困惑。

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 + + 的基本语法技能。 我想知道这些工作如何彻底和任何文件,我可以在互联网上得到的将比欢迎。(如果你能解释一下,那也会很棒的)。

30041 次浏览

_ Ty 是一个模板参数,在这种情况下

Object obj1;
Object obj2 = std::move(obj1);

_ Ty 是类型“ Object &”

这就是为什么需要 _ Remove_ 引用的原因。

更像是

typedef Object& ObjectRef;
Object obj1;
ObjectRef&& obj1_ref = obj1;
Object&& obj2 = (Object&&)obj1_ref;

如果我们不删除引用,就会像我们正在做的那样

Object&& obj2 = (ObjectRef&&)obj1_ref;

但 ObjectRef & & 还原为 Object & ,我们无法将其绑定到 objec2。

之所以减少这种方式是为了支持完美的转发。

We start with the move function (which I cleaned up a little bit):

template <typename T>
typename remove_reference<T>::type&& move(T&& arg)
{
return static_cast<typename remove_reference<T>::type&&>(arg);
}

Let's start with the easier part - that is, when the function is called with 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_referenceT&转换为 TT&&转换为 T,而 Object不是引用,因此我们的最终功能是:

Object&& move(Object&& arg)
{
return static_cast<Object&&>(arg);
}

现在,你可能会想: 我们真的需要演员吗?答案是: 是的,我们需要。原因很简单; 命名为 rvalue 引用 被视为 lvalue (标准禁止从 lvalue 到 rvalue 引用的隐式转换)。


Here's what happens when we call move with lvalue:

Object a; // a is lvalue
Object b = std::move(a);

and corresponding move instantiation:

// move with [T = Object&]
remove_reference<Object&>::type&& move(Object& && arg)
{
return static_cast<remove_reference<Object&>::type&&>(arg);
}

同样,remove_referenceObject&转换为 Object,我们得到:

Object&& move(Object& && arg)
{
return static_cast<Object&&>(arg);
}

现在我们进入棘手的部分: Object& &&是什么意思,它如何绑定到 lvalue?

To allow perfect forwarding, C++11 standard provides special rules for reference collapsing, which are as follows:

Object &  &  = Object &
Object &  && = Object &
Object && &  = Object &
Object && && = Object &&

正如您所看到的,在这些规则下,Object& &&实际上是指 Object&,它是允许绑定 lvalue 的普通 lvalue 引用。

最后的功能是:

Object&& move(Object& arg)
{
return static_cast<Object&&>(arg);
}

这与前面使用 rvalue 的实例化没有什么不同——它们都将其参数强制转换为 rvalue reference,然后返回它。区别在于,第一个实例化只能使用 rvalue,而第二个实例化使用 lvalue。


为了解释为什么我们更需要 remove_reference,让我们试试这个函数

template <typename T>
T&& wanna_be_move(T&& arg)
{
return static_cast<T&&>(arg);
}

并用 lvalue 实例化它。

// wanna_be_move [with T = Object&]
Object& && wanna_be_move(Object& && arg)
{
return static_cast<Object& &&>(arg);
}

Applying the reference collapsing rules mentioned above, you can see we get function that is unusable as move (to put it simply, you call it with lvalue, you get lvalue back). If anything, this function is the identity function.

Object& wanna_be_move(Object& arg)
{
return static_cast<Object&>(arg);
}