簡體   English   中英

用戶定義的轉換序列

[英]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構造Myclass1Myclass作為參數。

更新:

您可能會問為什么這樣做:

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更嚴格。 你應該使用那個開關 。)

其他編譯器(GCC,clang)拒絕它。

一旦您將副本初始化更改為直接初始化,所有編譯器都會接受代碼,如其他答案所示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM