Нашли или выдавили из себя код, который нельзя назвать нормальным,
на который без улыбки не взглянешь?
Не торопитесь его удалять или рефакторить, — запостите его на
говнокод.ру, посмеёмся вместе!
// https://habr.com/ru/company/yandex_praktikum/blog/555704/
// Стандарт C++20: обзор новых возможностей C++. Часть 2 «Операция ''Космический Корабль''»
// Предположим, вы определили структуру, содержащую одно число:
struct X {
int a;
};
// Мы хотим сделать так, чтобы значения этой структуры можно было сравнивать друг с другом.
// Для этого придётся написать шесть операций:
bool operator== (X l, X r) { return l.a == r.a; }
bool operator!= (X l, X r) { return l.a != r.a; }
bool operator>= (X l, X r) { return l.a >= r.a; }
bool operator<= (X l, X r) { return l.a <= r.a; }
bool operator< (X l, X r) { return l.a < r.a; }
bool operator> (X l, X r) { return l.a > r.a; }
// А теперь представьте, что мы хотим сравнивать элементы этой структуры не только между собой,
// но также с числами int. Количество операций возрастает с шести до 18:
bool operator== (X l, int r) { return l.a == r; }
bool operator!= (X l, int r) { return l.a != r; }
bool operator>= (X l, int r) { return l.a >= r; }
bool operator<= (X l, int r) { return l.a <= r; }
bool operator< (X l, int r) { return l.a < r; }
bool operator> (X l, int r) { return l.a > r; }
bool operator== (int l, X r) { return l == r.a; }
bool operator!= (int l, X r) { return l != r.a; }
bool operator>= (int l, X r) { return l >= r.a; }
bool operator<= (int l, X r) { return l <= r.a; }
bool operator< (int l, X r) { return l < r.a; }
bool operator> (int l, X r) { return l > r.a; }
// Что делать? Можно позвать штурмовиков. Их много, и они быстро напишут 18 операций.
// Или воспользоваться «космическим кораблём». Эту новую операцию в C++ называют
// «космический корабль», потому что она на него похожа: <=>. Более формальное название
// «трёхстороннее сравнение» фигурирует в документах Стандарта.
А можно добавить гомоиконность, которой можно наметушить не только какой-то там космический корабль (ради которого в крестокомпиляторах надо синтаксический анализатор менять, чтоб добавить новое синтаксиальное говно для этого <=>), а хоть целую, блядь, эскадрилью космических кораблей, которая работает не только для "больше меньше равно", но и для любой вообразимой поебени
Но крестушкам конечно привычней добавить какой-то ad-hoc хуиты для частных случаев.
То есть теперь не нужно вручную объяснять компилятору, что если A > B, то B < A, а можно сделать одну фцнкйию, которая вернет -1, 0 и 1? Типа "меньше", "равно", "больше"?
> То есть теперь не нужно вручную объяснять компилятору, что если A > B, то B < A, а можно сделать одну фцнкйию, которая вернет -1, 0 и 1? Типа "меньше", "равно", "больше"?
Нет, не совсем так. Это крестоговно, тут всё сложнее.
https://habr.com/ru/company/yandex_praktikum/blog/555704/#comment_23001838
> Это не совсем так, причина там в другом. Оператор <=> вообще никогда не генерирует операторы == и != сам по себе, он генерирует только <, >, <= и >=, при этом неважно, какой ордеринг применяется. Просто есть соглашение, что дефолтные операторы == и != генерируются как бы «в довесок», если оператор <=> определен как defaulted, а так операторы «сравнения» и «равенства» как бы логически разделены и независимы. Идея была в том, что к результату выполнения operator<=>() предъявляются определенные требования, которые могут быть игнорированы при сравнении «на равенство», скажем, векторов или строк. Можно определить, что один вектор не равен другому, просто сравнив длину, и если длины разные, то сразу остановиться. Поэтому было решено, что не следует пользоваться кастомной реализацией operator<=>() для создания дефолтной реализации операторов сравнения на строгое равенство. В случае кастомной реализации operator<=>() по-прежнему можно при желании явным образом определить operator==() как default и получить его (и != соответственно). Вот здесь подробнее написано:
Скажем, если взять какие-нибудь плавучиепитуховые числа, и сравнивать их, то если "false == (NaN == NaN)" и "false == (NaN < NaN)" то это еще не значит, что "true == (NaN > NaN)". Охуенно, не правда ли?
> В структуру X я добавил всего одну строчку, определяющую операцию <=>. Заметьте, что я даже не написал, что именно она делает:
#include <iostream>
struct X {
auto operator<=>(const X&) const = default; // <-- !
int a;
};
> И C++ всё сделал за меня. Это сработает и в более сложных случаях, например, когда у X несколько полей и базовых классов. При этом всё, что есть в X, должно поддерживать сравнение.
Да, охуеть конечно, ничего не скажешь. А под что-то кроме сравнения ее можно использовать? Почему надо под какую-то мелкую частную поебень со сравнением через "<" "==" ">" пилить какую-то частную хуйню?
Сам оператор нинужен, конечно. А вот = default для операторов сравнения выглядит вполне няшно, наконец-то не надо будет генерить эту фигню макросами и перечислять поля для сравнения вручную.
То есть теперь не нужно вручную объяснять компилятору, что если A > B, то B < A, а можно сделать одну фцнкйию, которая вернет -1, 0 и 1? Типа "меньше", "равно", "больше"?
Нет, не совсем так. Это крестоговно, тут всё сложнее.
> Это не совсем так, причина там в другом. Оператор <=> вообще никогда не генерирует операторы == и != сам по себе, он генерирует только <, >, <= и >=, при этом неважно, какой ордеринг применяется. Просто есть соглашение, что дефолтные операторы == и != генерируются как бы «в довесок», если оператор <=> определен как defaulted, а так операторы «сравнения» и «равенства» как бы логически разделены и независимы. Идея была в том, что к результату выполнения operator<=>() предъявляются определенные требования, которые могут быть игнорированы при сравнении «на равенство», скажем, векторов или строк. Можно определить, что один вектор не равен другому, просто сравнив длину, и если длины разные, то сразу остановиться. Поэтому было решено, что не следует пользоваться кастомной реализацией operator<=>() для создания дефолтной реализации операторов сравнения на строгое равенство. В случае кастомной реализации operator<=>() по-прежнему можно при желании явным образом определить operator==() как default и получить его (и != соответственно). Вот здесь подробнее написано:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1185r2.html
> В структуру X я добавил всего одну строчку, определяющую операцию <=>. Заметьте, что я даже не написал, что именно она делает:
> И C++ всё сделал за меня. Это сработает и в более сложных случаях, например, когда у X несколько полей и базовых классов. При этом всё, что есть в X, должно поддерживать сравнение.
Да, охуеть конечно, ничего не скажешь. А под что-то кроме сравнения ее можно использовать? Почему надо под какую-то мелкую частную поебень со сравнением через "<" "==" ">" пилить какую-то частную хуйню?
Но это не точно, потому что я это не использую. Самое ненужное добавление ИМХО. Лучше бы рефлексию запилили.
Сам оператор нинужен, конечно. А вот = default для операторов сравнения выглядит вполне няшно, наконец-то не надо будет генерить эту фигню макросами и перечислять поля для сравнения вручную.