[英]Why do I need to use std::move in the initialization list of a move-constructor?
假設我有一個(瑣碎的)類,它是可移動構造的和可移動分配的,但不能復制構造或可復制分配的類:
class movable
{
public:
explicit movable(int) {}
movable(movable&&) {}
movable& operator=(movable&&) { return *this; }
movable(const movable&) = delete;
movable& operator=(const movable&) = delete;
};
這工作正常:
movable m1(movable(17));
當然,這是行不通的,因為m1
不是右值:
movable m2(m1);
但是,我可以將m1
包裝在std::move
,將其強制轉換為右值引用,以使其正常工作:
movable m2(std::move(m1));
到現在為止還挺好。 現在,讓我們說我有一個(平凡的)容器類,它包含一個值:
template <typename T>
class container
{
public:
explicit container(T&& value) : value_(value) {}
private:
T value_;
};
但是,這不起作用:
container<movable> c(movable(17));
編譯器(我嘗試過clang 4.0和g ++ 4.7.2)抱怨我試圖在container
的初始化列表中使用movable
的deleteed-constructor。 同樣,將value
包裝在std::move
使其起作用:
explicit container(T&& value) : value_(std::move(value)) {}
但是為什么在這種情況下需要std::move
? value
已經不是movable&&
類型的value
了嗎? value_(value)
與movable m1(movable(42))
有何不同?
這是因為value
是一個命名變量,因此是一個左值。 需要std::move
將其強制轉換回右值,以使T
移動構造函數重載匹配。
換句話說:右值引用可以綁定到右值,但它本身不是右值。 它只是一個引用,在表達式中是一個左值。 從中創建右值表達式的唯一方法是強制轉換。
value_(value)
與movable m1(movable(42))
有何不同?
命名的右值引用是左值(因此將綁定到已刪除的副本ctor),而臨時表是右值(具體來說是prvalue)。
§5 [expr] p6
[...]通常,此規則的作用是將已命名的右值引用視為左值,將對對象的未命名的右值引用視為x值[...]
以及從示例:
A&& ar = static_cast<A&&>(a);
表達式
ar
是一個左值。
上面的引文來自非規范性注釋,但由於第5節的其余部分繼續說明了哪些表達式僅創建xvalues † (又名,僅指定的表達式而其他都不創建xvalue),因此提供了足夠的說明。 另請參閱此處以獲取詳盡列表。
†xvalues是rvalues的一個子組,而prvalues是rvalues的另一子組。 請參閱此問題以獲取解釋。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.