[英]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.