[英]Ternary operator applied to class with conversion operator and delete constructor causes ambiguity
struct A {
A();
A(int) = delete;
operator int();
};
int main() {
true ? A{} : 0;
}
使用 C++20 編譯,Clang 接受它,但 GCC 和 MSVC 拒絕它並顯示類似的錯誤消息
<source>(8): error C2445: result type of conditional expression is ambiguous: types 'A' and 'int' can be converted to multiple common types
<source>(8): note: could be 'A'
<source>(8): note: or 'int'
int
似乎不能轉換為A
因為構造函數是delete
,但我不確定為什么 GCC/MSVC 仍然認為它可以。 哪個編譯器是正確的?
(演示)
我認為 gcc 和 msvc 拒絕代碼是正確的,因為deleted
的 function 仍將參與重載解析。 這意味着有兩種可能性。
首先是A{}
可以通過轉換 function轉換為int
。 其次,即使0
不能轉換為A
,相應的轉換構造函數A::A(int)
仍將參與重載決議。 因此,存在歧義(關於轉換哪個操作數)並且程序不應編譯(如 GCC 和 MSVC)。
來自條件運算符的文檔:
[注意 2:諸如訪問、操作數是否為位字段或轉換 function 是否被刪除等屬性在該確定中被忽略。 ——尾注]
這似乎是CWG issue 1895的變體。
在其決議(2016 年使用 C++17)之前,相關措辭詢問是否可以將任一操作數“轉換”為由另一操作數的類型形成的目標類型。
根據問題描述,似乎這個原始措辭及其周圍的措辭在是否應考慮此轉換中使用的構造函數/轉換運算符的刪除方面有些模棱兩可,問題描述似乎表明嚴格閱讀會導致令人驚訝的不一致結果。 我不確切知道問題中的解釋如何適用於您的案例,但考慮到問題的作者,如果它與 Clang 的行為相匹配,我不會感到驚訝。
無論如何,問題的解決將措辭改為“是否可以形成隱式轉換序列”,這是符合重載決議的,並且明確地沒有考慮選擇的隱式轉換序列是否會實際導致轉換是格式良好,特別是所使用的功能是否可訪問/刪除。
@AnoopRana 在答案中引用的注釋也添加到該決議中以明確這一點。
新的寫法既可以形成A{}
到int
的轉換序列,也可以形成0
到A
的轉換序列,因此運算符是有歧義的。 MSVC 和 GCC 現在是正確的。
Clang 目前將缺陷報告 1895 的實施狀態列為“未知”( https://clang.llvm.org/cxx_dr_status.html ),並且仍然有一個與 CWG 問題描述相匹配的未解決錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.