[英]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_reference
將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的實例化沒有什么不同 - 它們都將其參數轉換為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.