[英]User-defined conversions sequence
在我研究explicit
關鍵字之前,我的老師說:“編譯器不執行連續的用戶定義轉換”。 如果是,我的代碼中是否有任何錯誤? 或者我誤解了我的老師? 我在VS2017工作。
#include<iostream>
#include <string>
class Myclass {
public:
Myclass() {
std::cout << "Myclass" << std::endl;
}
};
class Myclass1 {
public:
Myclass1(Myclass m) {
std::cout << "Myclass1" << std::endl;
}
};
class Myclass2{
public:
Myclass2(Myclass1 m) {
std::cout << "Myclass2" << std::endl;
}
};
int main() {
Myclass2 m2 = Myclass{};
}
編譯器不執行連續的用戶定義轉換
你的老師是對的。 在您的代碼示例中,這意味着當您分配時, Myclass
無法轉換為Myclass1
:
Myclass2 m2 = Myclass{};
因為構造Myclass1
在創建Myclass1
時需要Myclass2
,並且編譯器不能將Myclass
連續轉換為Myclass1
,然后使用它來創建Myclass2
。 但如果您有以下行:
Myclass1 m2 = Myclass{};
它會工作,因為Myclass1
構造Myclass1
將Myclass
作為參數。
更新:
您可能會問為什么這樣做:
Myclass2 m2 {Myclass{}};
因為在這種情況下,構造函數被調用並且可以隱式地進行轉換,除非您將Myclass1
聲明為explicit
,這將使代碼編譯失敗(感謝Fureeish提醒),但是:
Myclass2 m2 = Myclass{};
就像調用需要引用的copy-constructor一樣。 所以如果你這樣寫,它會工作:
Myclass2 m2 = Myclass1(Myclass{});
正如EVG所提到的, Myclass2 m2 = Myclass{};
如果未激活一致性模式(/ permissive-),則VS 2017接受。
這條線
Myclass2 m2 = Myclass{};
表示復制初始化 。 引用cppreference.com :
如果
T
是類類型,並且other
類型的cv-nonqualified版本不是T
或從T
[...]派生,則用戶定義的轉換序列可以從other
類型轉換為T
[...檢查並通過重載分辨率選擇最佳的一個。
進一步引用:
用戶定義的轉換由零個或一個非顯式單參數構造函數或非顯式轉換函數調用組成。
所以, Myclass2 m2 = Myclass{};
是不可接受的,因為它涉及兩個用戶定義的轉換。
現在讓我們來看看
Myclass2 m2 {Myclass{}};
在Afshin的回答中提出。 這是一個直接初始化 。 規則不同 :
檢查
T
的構造函數,並通過重載決策選擇最佳匹配。 然后調用構造函數來初始化對象。
Myclass2
的構造Myclass2
接受Myclass1
,您需要一個用戶定義的轉換才能從Myclass
獲取Myclass1
。 因此,它編譯。
請注意,在VS 復制中,如果未激活一致性模式( /premissive-
)(默認情況下),則會將其視為直接啟動。 所以,VS接受Myclass2 m2 = Myclass{};
將其視為直接啟動 。 有關示例,請參閱此文檔 。
其他答案正在埋葬lede:你寫的代碼確實無效 。 MSVC默認接受它,但MSVC這樣做是錯誤的。 您可以使用命令行開關/permissive-
強制MSVC更嚴格。 ( 你應該使用那個開關 。)
一旦您將副本初始化更改為直接初始化,所有編譯器都會接受代碼,如其他答案所示。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.