std :: move()如何将值传输到RValues? [英] How does std::move() transfer values into RValues?

查看:193
本文介绍了std :: move()如何将值传输到RValues?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



首先,我尝试了它,但似乎只有文档关于如何使用 std :: move()

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



std :: move()的定义如下。

 模板< class _Ty> inline 
typename tr1 :: _ Remove_reference< _Ty> :: _ Type&&&
move(_Ty& _Arg)
{// forward _Arg as movable
return((typename tr1 :: _ Remove_reference< _Ty> :: Type&&
}

首先对我来说奇怪的是参数(_Ty&& _Arg ),因为当我调用像下面的函数时,

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

它基本上等于

  // std :: move()
_Ty&&& _Arg = Obj1;

但是你已经知道,你不能直接链接一个LValue到RValue引用,认为它应该是这样的。

  _Ty&& _Arg =(Object&&)obj1; 

但是,这是荒谬的,因为std :: move()必须适用于所有的值。 p>

所以我想完全明白这是如何工作的,我也应该看看这些结构。

  template< class _Ty> 
struct _Remove_reference
{//删除引用
typedef _Ty _Type;
};

模板< class _Ty>
struct _Remove_reference< _Ty&>
{// remove reference
typedef _Ty _Type;
};

模板< class _Ty>
struct _Remove_reference< _Ty&&>
{// remove rvalue reference
typedef _Ty _Type;
};

不幸的是,它还是让人迷惑,我不知道。



我知道这是因为我缺乏C ++的基本语法技能。
我想知道这些工作如何彻底,任何文件,我可以在互联网上得到的欢迎。

解决方案

我们从move函数开始up a bit bit):

  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()是临时的,它是prvalue

和我们的 move 模板实例化如下:

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

由于 remove_reference T& T T& code> T Object 不是引用,我们的最终函数是:

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

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






下面是当我们使用lvalue调用 move 时会发生什么:

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

和对应的 move 实例化:

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

同样, remove_reference Object& 转换为对象,我们得到:

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



现在我们遇到棘手的部分:对象& &&&&&< / code>甚至意味着它如何绑定到lvalue?



为了允许完美的转发,C ++ 11标准提供了特殊的规则参考折叠,如下:

 对象& & = Object& 
Object& &&& = Object&
对象&& & = Object&
对象&& &&& =对象&&

正如你所看到的,根据这些规则 Object& &&&&&< / code>实际上是指 Object& ,它是允许绑定左值的纯逗号引用。



最终函数是:

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

这与使用rvalue的上一个实例化不一样 - 右值引用然后返回它。区别在于,第一个实例化只能与右值一起使用,而第二个实例化只能使用左值。






我们需要 remove_reference 多一点,让我们尝试这个函数

  < 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&&& amp; arg)
{
return static_cast< Object& &&>(arg);
}

应用上述参考折叠规则,可以看到不能用作 move (简单地说,你用左值调用它,你得到了左值)。如果有的话,这个函数是身份函数。

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


I just found myself not fully understanding the logic of std::move().

At first, I googled it but seems like there are only documents about how to use std::move(), not how its structure works.

I mean, I know what the template member function is but when I look into std::move() definition in VS2010, it is still confusing.

the definition of std::move() goes below.

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);
    }

What is weird first to me is the parameter, (_Ty&& _Arg), because when I call the function like you see below,

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

it basically equals to

// std::move()
_Ty&& _Arg = Obj1;

But as you already know, you can not directly link a LValue to a RValue reference, which makes me think that it should be like this.

_Ty&& _Arg = (Object&&)obj1;

However, this is absurd because std::move() must work for all the values.

So I guess to fully understand how this works, I should take a look at these structs too.

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;
};

Unfortunately it's still as confusing and I don't get it.

I know that this is all because of my lack of basic syntax skills about C++. I'd like to know how these work thoroughly and any documents that I can get on the internet will be more than welcomed. (If you can just explain this, that will be awesome too).

解决方案

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

and our move template gets instantiated as follows:

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

Since remove_reference converts T& to T or T&& to T, and Object is not reference, our final function is:

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

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).


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);
}

Again, remove_reference converts Object& to Object and we get:

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

Now we get to the tricky part: what does Object& && even mean and how can it bind to 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 &&

As you can see, under these rules Object& && actually means Object&, which is plain lvalue reference that allows binding lvalues.

Final function is thus:

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

which is not unlike the previous instantiation with rvalue - they both cast its argument to rvalue reference and then return it. The difference is that first instantiation can be used with rvalues only, while the second one works with lvalues.


To explain why do we need remove_reference a bit more, let's try this function

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

and instantiate it with 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);
}

这篇关于std :: move()如何将值传输到RValues?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆