内置运算符 == 重载的解析
Resolution of built-in operator == overloads
在下面的代码中,struct A
有两个到 char
和 int
的隐式转换运算符,并且比较结构的一个实例与整数常量 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。给了一个和你类似的例子,提交者解释说按照标准,重载解析是有歧义的,尽管这个结果很counter-intuitive.
转换为您的特定示例,在比较 operator==(int, int)
和 operator==(float, int)
以确定哪个是更好的候选者时,我们必须确定哪个对第一个参数具有更好的隐式转换序列(显然在第二个参数中,不需要转换)。对于 operator==(int, int)
的第一个参数,我们只使用 A::operator int
。对于operator==(float, int)
的第一个参数,没有办法决定是使用A::operator int
还是A::operator char
,所以我们得到了“歧义转换序列”。重载决议规则表明,不明确的转换序列并不比任何其他 user-defined 转换序列更好或更差。因此,从 A{}
到 int
的直接转换(通过 A::operator int
)并不被认为比从 A{}
到 float
的模糊转换更好。这意味着 operator==
候选人都不比另一个更好。
Clang 显然遵循标准的字面意思,而 GCC 和 MSVC 可能正在做其他事情,因为标准似乎在这里被打破了。 “哪个编译器是正确的”取决于您对标准应该的看法。问题页面上没有建议的解决方案。
我建议删除 operator char
除非你真的、真的需要它,在这种情况下你将不得不考虑你还愿意放弃什么。
在下面的代码中,struct A
有两个到 char
和 int
的隐式转换运算符,并且比较结构的一个实例与整数常量 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。给了一个和你类似的例子,提交者解释说按照标准,重载解析是有歧义的,尽管这个结果很counter-intuitive.
转换为您的特定示例,在比较 operator==(int, int)
和 operator==(float, int)
以确定哪个是更好的候选者时,我们必须确定哪个对第一个参数具有更好的隐式转换序列(显然在第二个参数中,不需要转换)。对于 operator==(int, int)
的第一个参数,我们只使用 A::operator int
。对于operator==(float, int)
的第一个参数,没有办法决定是使用A::operator int
还是A::operator char
,所以我们得到了“歧义转换序列”。重载决议规则表明,不明确的转换序列并不比任何其他 user-defined 转换序列更好或更差。因此,从 A{}
到 int
的直接转换(通过 A::operator int
)并不被认为比从 A{}
到 float
的模糊转换更好。这意味着 operator==
候选人都不比另一个更好。
Clang 显然遵循标准的字面意思,而 GCC 和 MSVC 可能正在做其他事情,因为标准似乎在这里被打破了。 “哪个编译器是正确的”取决于您对标准应该的看法。问题页面上没有建议的解决方案。
我建议删除 operator char
除非你真的、真的需要它,在这种情况下你将不得不考虑你还愿意放弃什么。