内置运算符的解析==重载

Resolution of built-in operator == overloads

本文关键字:重载 运算符 内置      更新时间:2024-09-22

在以下代码中,struct A有两个到charint的隐式转换运算符,并将结构的实例与整数常量2:进行相等性比较

struct A {
constexpr operator char() { return 1; }
constexpr operator int() { return 2; }
};
static_assert( A{} == 2 );

代码在GCC和MSVC中通过得很好,但Clang抱怨道:

<source>:5:20: error: use of overloaded operator '==' is ambiguous (with operand types 'A' and 'int')
static_assert( A{} == 2 );
~~~ ^  ~
<source>:5:20: note: because of ambiguity in conversion of 'A' to 'float'
<source>:2:15: note: candidate function
constexpr operator char() { return 1; }
^
<source>:3:15: note: candidate function
constexpr operator int() { return 2; }
^
<source>:5:20: note: built-in candidate operator==(float, int)
static_assert( A{} == 2 );
^
<source>:5:20: note: built-in candidate operator==(double, int)
<source>:5:20: note: built-in candidate operator==(long double, int)
<source>:5:20: note: built-in candidate operator==(__float128, int)
<source>:5:20: note: built-in candidate operator==(int, int)
...

演示:https://gcc.godbolt.org/z/h9Kd66heM

一般的问题是哪一个编译器在这里?特别有趣的是,Clang为什么不喜欢operator==(int, int),却把它列在其他列表中?

这是CWG 507。给出了一个类似于你的例子,提交者解释说,根据标准,过载解决方案是模糊的,尽管这个结果非常违背直觉。

转化为您的特定示例,当比较operator==(int, int)operator==(float, int)以确定哪一个是更好的候选者时,我们必须确定哪一个中第一个参数的隐式转换序列更好(显然在第二个参数中,不需要转换(。对于operator==(int, int)的第一个自变量,我们只使用A::operator int。对于operator==(float, int)的第一个自变量,没有办法决定是使用A::operator int还是使用A::operator char,因此我们得到";模糊转换序列";。重载解析规则表示,不明确的转换序列并不比任何其他用户定义的转换序列更好或更差。因此,从A{}int的直接转换(通过A::operator int(并不被认为比从A{}float的模糊转换更好。这意味着两个operator==候选都不比另一个好。

Clang显然遵循了标准的字母,而GCC和MSVC可能正在做其他事情,因为这里的标准似乎被打破了"哪个编译器是对的";取决于您对标准应该说什么的看法。问题页面上没有拟议的解决方案。

我建议删除operator char,除非你真的、真的需要它,在这种情况下,你必须考虑你还愿意放弃什么。