В C++23 класс может иметь явные функции-члены объекта (с префиксом this
перед первым параметром), включая операторы сравнения членов. Какие из них компилятор может сгенерировать автоматически после указания =default
?
Я ожидал, что любой действительный оператор сравнения по умолчанию для друзей будет иметь аналогичный действительный оператор сравнения по умолчанию для явного члена объекта (после замены friend
на this
). Но на практике с нынешними компиляторами это не так.
Первый пример:
struct A {
// ok everywhere
friend bool operator ==(A, A) = default;
// #1, ok in GCC, error in Clang
bool operator ==(this A, A) = default;
};
Здесь определение дружественного оператора принимается всеми компиляторами, но только GCC допускает #1, и Clang жалуется:
<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;
Онлайн-демо: https://gcc.godbolt.org/z/qjTavxWv6
Во втором примере:
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;
};
Аналог недопустимого оператора друга принимается в Clang, а GCC отклоняет его:
<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;
Онлайн-демо: https://gcc.godbolt.org/z/4r3q9fTrh
Какие из явно заданных по умолчанию операторов (№1 или №2) действительно действительны?
Формулировка в [class.compare.default] довольно ясна:
Функция оператора сравнения по умолчанию ([over.binary]) должна быть нешаблонной функцией, которая
- является нестатическим участником или другом какого-либо класса
C
,- определяется как значение по умолчанию в
C
или в контексте, гдеC
завершено, и- либо имеет два параметра типа
const C&
, либо два параметра типаC
, где неявный параметр объекта (если есть) считается первым параметром.
Итак, это действительно:
struct A {
bool operator ==(this A, A) = default;
};
и это не:
struct A {
bool operator ==(this const A, const A &) = default;
};