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

Fed*_*dor 11 c++ language-lawyer overload-resolution implicit-conversion

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

struct A {
    constexpr operator char() { return 1; }
    constexpr operator int() { return 2; }
};
static_assert( A{} == 2 );
Run Code Online (Sandbox Code Playgroud)

代码在 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)
...
Run Code Online (Sandbox Code Playgroud)

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

一般问题是这里哪个编译器?尤其有趣的是,为什么 Clang 不喜欢operator==(int, int),而是将其列出来?

Bri*_*ian 14

这是CWG 507。给出了一个与您类似的例子,提交者解释说,根据标准,重载解析是不明确的,尽管这个结果非常违反直觉。

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

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

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