C++23 中类的比较运算符是否可以具有与类类型不同的类型的显式对象参数?
考虑例如
struct A {
int i;
constexpr bool operator==(this int x, int y) { return x == y; }
constexpr operator int() const { return i; }
};
现在比较不平等
static_assert( A{0} != A{1} );
被 GCC 和 Clang 接受,但 MSVC 抱怨:
error C2803: 'operator ==' must have at least one formal parameter of class type
error C2333: 'A::operator ==': error in function declaration; skipping function body
以及平等比较
static_assert( A{2} == A{2} );
仅被 GCC 接受,而 Clang 已经不喜欢它了:
error: use of overloaded operator '==' is ambiguous (with operand types 'A' and 'A')
11 | static_assert( A{2} == A{2} );
note: candidate function
3 | constexpr bool operator==(this int x, int y) { return x == y; }
note: built-in candidate operator==(int, int)
在线演示:https://gcc.godbolt.org/z/dnKc1fhcT
这里哪个编译器是正确的?
据我所知:
MSVC的错误不正确。 [over.oper.general]/7 仅对非成员重载的参数类型提出要求。显式对象参数函数是成员函数。
Clang 的错误信息是正确的。
operator==(int, int)
有一个内置的 ==
候选者,这并不比任何重载消歧所产生的 operator==
重载更好或更差。如果内置候选者具有与非成员候选者之一匹配的参数类型列表,则 [over.match.oper]/3.3.4 会排除内置候选者,但同样,仅适用于 non-member 候选者并且具有显式对象参数的重载是成员候选者。
在
static_assert( A{0} != A{1} );
的情况下,没有问题,因为与使用 operator!=(int, int)
重载的任何重写候选者相比,这会更喜欢内置 operator==
候选者。 GCC 和 Clang 都会忽略您的过载。