簡體   English   中英

轉換運算符vs刪除的構造函數

[英]Conversion operator vs deleted constructor

請參見以下代碼:

struct X;

struct Y {
  Y() {}
  Y(X&) = delete;
};

struct X {
  X() {}
  operator Y() {
    return{};
  }
};

int main() {
  X x;
  static_cast<Y>(x);
}

在這里,顯式刪除了使用XY的構造函數,而X將轉換運算符轉換為Y 在這兩個直接矛盾的地方,似乎=delete總是贏; 我在GCC,Clang和VC ++的某些最新版本上進行了測試。

問題:這是“正確的”行為嗎? 我認為轉換構造函數和轉換運算符之間沒有特殊的優先級,因此上面的代碼應產生重載解析度歧義錯誤。 但事實並非如此。 它抱怨刪除功能的使用。 是因為可以保證復制保留嗎?

我用谷歌搜索,發現轉換構造函數與轉換運算符:priority 在該問題中,選擇了轉換運算符,因為由於轉換構造const中存在const ,因此它更匹配。 但是,在我的情況下,將Y(X&)替換為Y(X const&)沒有改變。


實際上,我想要的情況如下:

X x;
Y y1(x);                  // Error
Y y2 = static_cast<Y>(x); // OK

是的,這可能很愚蠢,但是確實有一些內置類型的行為就像這樣: X <- int&Y <- int&& 無法創建完全模仿內置引用類型的用戶定義類型似乎是當前C ++迫切需要的部分...

從標准11.6.17.6.2

如果初始化是直接初始化,或者如果復制是初始化,則源類型的cv不合格版本與目標的類相同,或者是該類的派生類,則考慮構造函數。

然后標准告訴我們( 11.6.16

各種形式的初始化以及new表達式(8.5.2.4), static_cast表達式(8.5.1.9),功能符號類型轉換(8.5.1.3),mem初始化器(15.6.2) ,條件的括號初始列表形式稱為直接初始化。

您的示例通過static_cast初始化了一個臨時項,因此由於直接初始化,編譯器只允許使用構造函數,因此會出現錯誤。

問題:這是“正確的”行為嗎? 我以為轉換構造函數和轉換運算符之間沒有特別的優先級[...]

那不是很正確。 您正在按原樣查看代碼:

struct Y {
  Y() {}
  Y(X&) = delete;
};

但實際上還有更多的東西。 對於編譯器, Y看起來像:

struct Y {
  Y() {}
  Y(X&) = delete;

  Y(Y&&) = default;
  Y(Y const&) = default;
};

這里的選擇不在Y(X&)X::operator Y() 選擇主要在Y(X&)Y(Y&&) 而且前者比后者更好(不管,正如您在問題中提到的那樣,它都是X&X const&作為參數)。 但是它已被刪除,因此轉換格式錯誤。


如果我們是復制初始化而不是直接初始化:

Y y = x;

那么兩者將是同樣可行的(因此模棱兩可)。 是的,您真的希望這個模棱兩可。 = delete不會從候選集中刪除!

將構造函數從Y(X&)更改為Y(X const&)將具有首選的轉換功能。


是的,這可能很愚蠢,但是確實有一些內置類型的行為就像這樣: X <- int&Y <- int&&

是的,但是在原始示例中, XY是不同的類型 在這里,它們代表相同類型的不同值類別。 這個新示例起作用或不起作用的原因完全不同:

X x;
Y y1(x);                  // Error
Y y2 = static_cast<Y>(x); // OK

是真的:

int& x = ...;
int&& y(x);                       // error, can't bind rvalue reference to lvalue
int&& y2 = static_cast<int&&>(x); // ok. this is exactly std::move(x)

與引用兼容類型的引用綁定與轉換優先級的問題不同。

暫無
暫無

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

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