我今天偶然發現了代碼,我不明白。請考慮以下示例:
#include <iostream>
#include <string>
class A
{
public:
template <class Type>
Type& operator=(Type&& theOther)
{
text = std::forward<Type>(theOther).text;
return *this;
}
private:
std::string text;
};
class B
{
public:
B& operator=(B&& theOther)
{
text = std::forward<B>(theOther).text;
return *this;
}
private:
std::string text;
};
int main()
{
A a1;
A a2;
a2 = a1;
B b1;
B b2;
b2 = b1;
return 0;
}
編譯時,MinGW-w64/g 10.2 宣告:
..\src\Main.cpp: In function 'int main()':
..\src\Main.cpp:41:7: error: use of deleted function 'B& B::operator=(const B&)'
41 | b2 = b1;
| ^~
..\src\Main.cpp:19:7: note: 'B& B::operator=(const B&)' is implicitly declared as deleted because 'B' declares a move constructor or move assignment operator
19 | class B
| ^
mingw32-make: *** [Makefile:419: Main.o] Error 1
我完全理解錯誤資訊。但我不明白為什么我沒有收到與 class 相同的訊息A。模板化的移動賦值運算子不也是移動賦值運算子嗎?為什么復制賦值運算子沒有被洗掉?這是寫得很好的代碼嗎?
uj5u.com熱心網友回復:
模板化移動賦值運算子不也是移動賦值運算子嗎?
不,它不被視為移動賦值運算子。
(強調我的)
類T的移動賦值運算子是一個非模板的名稱非靜態成員函式
operator=的是采用型別的正好一個引數T&&,const T&&,volatile T&&,或const volatile T&&。
結果,A仍然具有隱式宣告的復制/移動賦值運算子。
順便說一句:您的模板賦值運算子采用轉發參考,它可以接受左值和右值。在 中a2 = a1;,它在多載決議中戰勝了生成的復制賦值運算子并被呼叫。
uj5u.com熱心網友回復:
作為對@songyuanyao 基于標準的回答的補充:這些語言規則是 MISRA/AUTOSAR(安全關鍵 C 開發的語言指南)等指南具有“避免開發人員混淆”規則的常見原因,例如:
(來自AUTOSAR C 14 指南)
規則 A14-5-1(必需、實施、自動化)
模板建構式不應參與封閉型別別的單個引數的多載決議。
基本原理
模板建構式從來都不是復制或移動建構式,因此即使模板建構式看起來很相似并且很容易混淆,也不會阻止復制或移動建構式的隱式定義。同時,復制或移動操作不一定只使用復制或移動建構式,而是通過正常的多載決議程序來找到要使用的最佳匹配函式。在以下情況下,這可能會導致混淆:
- 沒有選擇看起來像復制/移動建構式的模板建構式
- 對于復制/移動操作,因為編譯器生成了隱式復制/移動建構式,并且模板建構式優先于復制/移動建構式被選擇,因為模板建構式是更好的匹配
為了避免這些令人困惑的情況,模板建構式不應參與封閉型別別的單個引數的多載決議,以避免為復制/移動操作選擇模板建構式。它還清楚地表明建構式不是復制/移動建構式,并且它不會阻止復制/移動建構式的隱式生成。
規則 M14-5-3(必需、實施、自動化)
當模板賦值運算子的引數為泛型引數時,應宣告復制賦值運算子。
也就是說,對于開發人員來說,模板復制/移動建構式/賦值運算子不會抑制(/不“激活”規則為 5)隱式生成的那些,這可能會令人驚訝。您通常需要使用 SFINAE 來確保模板化的建構式/賦值操作不會像復制/移動建構式/賦值一樣通過允許多載對于封閉類的單個引數處于活動狀態。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/339713.html
上一篇:如何使用混合分隔符(即方括號、空格和雙引號)來決議日志(nginx/apacheaccess.log)?并可選擇轉換為json
