2011-03-20 19 views
3

考慮這個小例子:衍生賦值運算符和完美轉發

include <iostream> 

struct foo 
{ 
     foo &operator=(const foo &) 
     { 
       std::cout << "base copy assignment\n"; 
       return *this; 
     } 
     foo &operator=(foo &&) 
     { 
       std::cout << "base move assignment\n"; 
       return *this; 
     } 
}; 

struct bar: foo 
{ 
     template <typename T> 
     bar &operator=(T &&x) 
     { 
       std::cout << "derived generic assignment\n"; 
       foo::operator=(std::forward<T>(x)); 
       return *this; 
     } 
}; 

int main() 
{ 
    bar b, c; 
    b = c; 
    b = bar{}; 
} 

這個程序的輸出是:

derived generic assignment 
base copy assignment 
base move assignment 

,而我希望它是:

derived generic assignment 
base copy assignment 
derived generic assignment 
base move assignment 

或者換句話說,似乎bar中operator =()的完美轉發在移動賦值的情況下不會踢:改爲調用基本移動賦值運算符。

我試圖用一個簡單的構件功能相同的測試和在這種情況下,結果被作爲我期望(即,在列中的完美轉發分配總是之前的任何基底分配調用)。此外,與GCC 4.5相比,我目前使用的4.6版預發行版本的行爲也如我所料。

這是預期的行爲,具體到賦值運算符或這是一個最近的海灣合作委員會的錯誤?

回答

2

我起初回答不正確。我相信你得到的輸出是正確的。在bar中隱式生成一個移動賦值操作符,這就是你在第二個任務中調用的內容。隱式移動賦值運算符比您的顯式泛型運算符更好匹配。

還有一個隱式拷貝賦值運算符,但在這種情況下,泛型賦值運算符更好匹配,因爲c不是const

闡述:

一個隱含的舉動賦值運算符的產生,如果用戶宣佈拷貝賦值運算符,移動賦值運算符,拷貝構造函數,構造運動和析構函數只是抑制。這些特殊成員都不能成爲模板。 [class.copy]枚舉每個這些特殊成員的表單。

例如,對於X類的舉動賦值運算符將具有下列形式之一:

operator=(X&&); 
operator=(const X&&); 
operator=(volatile X&&); 
operator=(const volatile X&&); 

(任何返回類型都可以使用)。

bar中的模板化賦值運算符不符合特殊成員的條件。它不是複製賦值操作符也不是移動賦值操作符。

+1

我認爲定義賦值運算符會停止隱式生成賦值運算符嗎? – Clinton 2011-03-20 14:33:36

+0

您的評論是一個很好的評論。我詳細闡述了我的答案,試圖解決您的意見。我只是想將評論添加爲評論,但格式問題促使我改爲編輯答案。 – 2011-03-20 15:27:30

+0

非常感謝您的解釋和參考,我正在接受答覆。 – bluescarni 2011-03-20 18:52:04