簡體   English   中英

std :: move()如何將值傳遞給RValues?

[英]How does std::move() transfer values into 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_referenceT&轉換為TT&&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_referenceObject&轉換為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的實例化沒有什么不同 - 它們都將其參數轉換為rvalue引用然后返回它。 不同之處在於,第一個實例化只能與rvalues一起使用,而第二個實例化可以與左值一起使用。


為了解釋為什么我們需要更多的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是“對象&”類型

這就是_Remove_reference是必要的原因。

它會更像

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

如果我們沒有刪除引用,那就像我們正在做的那樣

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

但ObjectRef &&縮減為Object&,我們無法綁定到obj2。

它減少這種方式的原因是支持完美轉發。 本文

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM