2012-03-17 39 views
14

此問題來自this answer提出的問題。使用值而不是引用的賦值運算符的分支

通常,我們定義T類型的複製賦值運算符爲T& operator=(const T&),並將類型爲T的賦值運算符移動爲T& operator=(T&&)

但是,當我們使用值參數而不是參考時會發生什麼?

class T 
{ 
public: 
    T& operator=(T t); 
}; 

這應該使T既複製和移動assignable。但是,我想知道的是T的語言分歧是什麼?

具體做法是:

  1. 根據規範這個計數爲T一個拷貝賦值運算符,難道?
  2. 根據規範,這是否算作T的移動賦值運算符?
  3. T有一個編譯器生成的複製賦值運算符?
  4. T有一個編譯器生成的移動賦值運算符?
  5. 這對像std::is_move_assignable這樣的特徵類有什麼影響?
+0

相關討論:http://cpp-next.com/archive/2009/08/want-speed-pass-by-value – mavam 2012-03-17 17:06:28

+0

我在Visual Studio和g ++上都得到編譯器錯誤,如果我有T&operator = (T t)和T&operator =(T && t),因爲它是含糊的 – user929404 2013-05-05 16:06:01

+0

@ user929404:你應該。重點是,你只需要賦值就可以替換複製和移動賦值。 – 2013-05-06 00:33:51

回答

14

大部分內容在§12.8中描述。第17段定義爲用戶聲明的拷貝賦值運算符什麼罪名:

用戶聲明的拷貝賦值運算符X::operator=X類的非靜態的非模板成員函數X型,X&的只有一個參數, const X&volatile X&const volatile X&

第19段定義爲用戶聲明的舉動賦值運算符什麼罪名:

用戶聲明的舉動賦值運算符X::operator=X類的非靜態 非模板成員函數只有一個參數 類型X&&,const X&&volatile X&&const volatile X&&

因此,它計算爲複製賦值運算符,但不作爲移動賦值運算符。

第18段講述當編譯器生成的拷貝賦值運算符:

如果類定義不明確聲明拷貝賦值操作符 ,一個是隱式聲明。如果類定義聲明瞭 移動構造函數或移動賦值運算符,則隱式聲明的 聲明的複製賦值運算符被定義爲刪除;否則,它被定義爲默認(8.4)。如果 類具有用戶聲明的拷貝構造函數或用戶聲明的析構函數,則不推薦使用後一種情況。

第20段告訴我們,當編譯器生成移動賦值運算符:

如果一個類X的定義不明確宣佈的舉動 賦值運算符,一個將被隱式聲明爲默認如果 且僅當
[...]
- X沒有一個用戶聲明的拷貝賦值運算符,
[...]

由於該類具有用戶聲明的複製賦值運算符,因此編譯器不會生成任何隱式的賦值運算符。

std::is_copy_assignablestd::is_move_assignable在表49中被描述爲分別具有與is_assignable<T&,T const&>::valueis_assignable<T&,T&&>::value相同的值。該表告訴我們,is_assignable<T,U>::valuetrue時:處理 作爲未計算的操作數(第5章)時

表達declval<T>() = declval<U>()是良好的。如果在與TU無關的上下文中訪問檢查執行爲 。只考慮分配表達式的直接上下文的有效性。

由於兩個declval<T&>() = declval<T const&>()declval<T&>() = declval<T&&>()都能很好地形成爲階級,它仍然被認爲拷貝分配和移動分配。

正如我在評論中提到的那樣,對於這一切有什麼好奇的是,在存在移動構造函數的情況下,operator=將正確執行移動,但在技術上不算作移動賦值運算符。如果這個類沒有拷貝構造函數,它就更加奇怪了:它將有一個拷貝賦值操作符,它不會拷貝,而只是移動。