In C++23 a class can have explicit object member functions (with the first parameter prefixed by this
), including member comparison operators. Which of them a compiler can generate automatically after specifying =default
?
My expectation was that any valid friend defaulted comparison operator will have similar valid explicit object member defaulted comparison operator (after replacing friend
with this
). But on practice with the current compilers it is not so.
First example:
struct A {
// ok everywhere
friend bool operator ==(A, A) = default;
// #1, ok in GCC, error in Clang
bool operator ==(this A, A) = default;
};
Here friend operator definition is accepted by all compilers, but only GCC permits #1, and Clang complains:
<source>:5:22: error: defaulted member equality comparison operator must be const-qualified
5 | bool operator ==(this A, A) = default;
| ^
| const
<source>:5:10: error: invalid parameter type for defaulted equality comparison operator; found 'A', expected 'const A &'
5 | bool operator ==(this A, A) = default;
Online demo: https://gcc.godbolt.org/z/qjTavxWv6
In the second example:
struct A {
// fails everywhere
//friend bool operator ==(const A, const A &) = default;
// #2, ok in Clang, error in GCC
bool operator ==(this const A, const A &) = default;
};
The counterpart for the invalid friend operator is accepted in Clang, while GCC denies it:
<source>:5:10: error: defaulted 'bool A::operator==(this A, const A&)' must have parameters of either type 'const A&' or 'A', not both
5 | bool operator ==(this const A, const A &) = default;
Online demo: https://gcc.godbolt.org/z/4r3q9fTrh
Which of explicitly defaulted operators (#1 or #2) are actually valid?
The wording in [class.compare.default] is pretty clear:
A defaulted comparison operator function ([over.binary]) shall be a non-template function that
- is a non-static member or friend of some class
C
,- is defined as defaulted in
C
or in a context whereC
is complete, and- either has two parameters of type
const C&
or two parameters of typeC
, where the implicit object parameter (if any) is considered to be the first parameter.
So this is valid:
struct A {
bool operator ==(this A, A) = default;
};
and this is not:
struct A {
bool operator ==(this const A, const A &) = default;
};