2012-10-06 26 views
11

最近,我按照關於分配到在C++如以下示例中所示的表達式的討論:我應該爲賦值運算符使用左值引用限定符嗎?

string s1, s2, s3; 
(s1 + s2) = s3; 

用C++ 11也能夠限制賦值操作符到左值的引用(在左側)。當聲明賦值運算符如下所示時,由於不兼容的類型,編譯器Clang會拒絕代碼並顯示錯誤消息。

auto operator=(const string& rhs) & -> string&; 
auto operator=(string&& rhs) & -> string&; 

我還沒有見過這個地方。對賦值操作符不使用左值引用限定符是否有很好的理由(除了在大多數編譯器中缺少支持)?

+5

原因之一是大多數編譯器還不支持語法。另一個是它不能解決*重大問題。這種錯誤發生的頻率如何? –

+1

我認爲它確實發生。 'if(somefunc()= value)'當然,大多數編譯器會爲此發出警告,但不是所有情況。 –

回答

4

不,不是真的。使用左值或右值限定詞爲左值或右值對象構造正確的接口與使用const相同,並且應該以同樣的方式處理它 - 每個函數都應該考慮限制。賦值給右值並不合理,所以它應該被禁止。

你還沒有看到它的原因是編譯器大部分是窮人支持 - 爲*this右值裁判是有點像thread_local,大多數編譯器實現者似乎已經把它靠近底部的「功能從C++ 11實現」疊加。

+0

在我看來是最好的答案。雖然我對賦值運算符更感興趣,因爲它是一個特殊的成員函數。使用引用限定符可能對5規則,繼承,作爲聚合的成員變量或標準容器和標準庫的使用有一些影響。但是,我應該一直在尋求這些信息。 – nosid

8

有趣!我甚至沒有意識到這一點,並帶我一會兒找到它(這是"Extending move semantics to *this"提案的一部分)。符號在8.3.5 [dcl.decl]第4段中定義,以防有人想要查看。

無論如何:現在,知道這個特性,它似乎是最有用的使用它的重載,並可能有不同的行爲,如果一個函數被調用的對象是一個左值或右值。使用它來限制可以完成的任務,例如分配的結果似乎是不必要的,特別是如果對象實際上是左值。例如,您可能希望語法從分配給右值返回右值:

struct T { 
    auto operator=(T&) & -> T&; 
    auto operator=(T&&) & -> T&; 
    auto operator=(T&) && -> T; 
    auto operator=(T&&) && -> T; 
}; 

這樣做的目的是使從分配結果移動(這是否是值得的,不過,我不當然:爲什麼不首先跳過作業?)。我不認爲我會主要使用此功能來限制使用。

就我個人而言,我喜歡有時候可以從右值中獲得左值,賦值運算符通常是一種方法。例如,如果你需要一個左值傳遞給函數,但你知道你不希望使用任何與它,你可以使用一個左值的賦值操作符弄個:

#include <vector> 
void f(std::vector<int>&); 
int main() 
{ 
    f(std::vector<int>() = std::vector<int>(10)); 
} 

這可能是一個濫用轉讓經營者從右值中獲得左值,但不太可能偶然發生。因此,我不會因爲限制賦值運算符僅適用於左值而使這一點變得不可能。當然,從一個賦值返回一個右值也會阻止這個。這兩種用途中的哪一種更有用,如果有的話,可能是一個考慮因素。

順便說一句,鏗鏘似乎支持你從2.9版引用的語法。

+5

我寧願有一個明確的'template T&as_lvalue(T && v){return v; }的功能,而不是與我的同行編程人員的思想搞混了,這些編程人員不知道你試圖通過賦值達到什麼樣的目的(對於移動而言,它似乎還包含了一個無用的「vector」副本)。 – Xeo

3

我不是超級愛好者對你的建議的一個原因是I'm trying to shy away from declaring special members altogether。我的大多數賦值操作符因此被隱式聲明,因此沒有ref限定符。

當然,當我寫一個類或類模板到例如管理所有權(參見上述鏈接中的結論),我可以小心地僅將這些運營商聲明爲左值。因爲它對客戶沒有任何影響,所以沒有太大的意義。

+0

我同意你的意見。如果可能,我避免聲明任何5.然而,編譯器生成的賦值運算符不限於左值引用。最有可能是向後兼容的。 – nosid