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)
候选,根据任何过载歧义消除==
,它都不会比您的过载更好或更差。如果[over.match.oper]/3.3.4具有与非成员候选之一匹配的参数类型列表,则会排除内置候选,但同样,仅适用于非成员候选,并且具有显式对象参数的过载是成员候选。operator==
如果
static_assert( A{0} != A{1} );
没有问题,因为这将优先使用内置operator!=(int, int)
候选,而不是使用您的重载的任何重写候选operator==
。GCC 和 Clang 都会忽略您的重载。这意味着允许此类重载,但实际用途有限,因为它们与内置候选者大多存在歧义。也许[over.match.oper]/3.3.4也应适用于成员函数,而是将参数列表与对象参数进行比较。