2012-04-19 132 views
2

有人可以解釋爲什麼B不編譯,但C呢?我不明白爲什麼std :: move是必需的,因爲變量已經是右值ref。rvalue refs和std :: move

struct A { 
    int x; 
    A(int x=0) : x(x) {} 
    A(A&& a) : x(a.x) { a.x = 0; } 
}; 

struct B : public A { 
    B() {} 
    B(B&& b) : A(b) {} // compile error with g++-4.7 
}; 

struct C : public A { 
    C() {} 
    C(C&& c) : A(std::move(c)) {} // ok, but why? 
}; 
+0

接受一個答案! – Walter 2012-11-30 14:25:30

回答

12

因爲命名變量不是右值,宣佈& &時也是如此。如果它有一個名稱,那麼它不是暫時的,因此您需要使用std::move

21

在聲明中:

B(B&& b) 

參數b聲明與類型:右值引用B

在語句:

A(b) 

表達bB類型的左值。

而左值表達式不能結合rvalue引用:特別是在語句中的右值參考:

A(A&& a) 

此邏輯乾淨地從語言的其他部分如下。考慮一下這個功能:

void 
f(B& b1, B b2, B&& b3) 
{ 
    g(b1); 
    g(b2); 
    g(b3); 
} 

即使的f參數都聲明與不同類型的表達式b1b2b3B類型的所有左值表達式,從而將所有調用同一個函數g,無重要的是如何g過載。

在C++ 11中,區分變量的聲明和使用該變量的表達式比以往任何時候都更加重要。表達式從來沒有引用類型。相反,它們有一個值爲的值類別,其正是以下值之一:左值,左值,右值。

聲明:

A(std::move(c)) 

是確定的,因爲std::move返回一個右值引用。函數調用返回右值引用的表達式具有值類別:xvalue。與prvalues一起,xvalues被視爲rvalues。和C類型的右值表達式:

std::move(c) 

將結合在右值參考參數:A(A&& a)

我發現下面的圖(最初由Bjarne Stroustrup的發明)非常有幫助:

 expression 
     /\ 
    glvalue rvalue 
    /\ /\ 
lvalue xvalue prvalue 
+0

感謝您的詳細解答。顯然這裏有很多細微的東西需要理解。 – drwowe 2012-04-23 15:16:06