автоматическая генерация некоторых операторов, имея в наличии противоположные
Если в некотором классе определены операторы < ==, что мешает компилятору автоматически генерировать операторы <=, >, >=, !=? Насколько я помню, где то в стандартной библиотеке даже определены такие шаблонные операторы, а в стандартных итераторах определены все эти операторы как:
если b < a, то a > b, если !(b < a) то a >= b и так далее
Зачем это писать, если можно пользоваться общим шаблоном? И почему современные компиляторы не могут просто понять это, зная что такое меньше и зная что такое равно?...
Ответы (2 шт):
Уже ничего, в С++20 примерно так и происходит (только вместо < == нужны <=> ==).
https://ru.stackoverflow.com/questions/924217/Оператор-эквивалентности/924245#924245
Если в некотором классе определены операторы < ==, что мешает компилятору автоматически генерировать операторы <=, >, >=, !=?
Например, то, что логика класса может быть отлична от "человеческой логики". Как компилятор будет добавлять логику в ваш класс, если вы явно указали, что класс поддерживает только < и ==? Изначально, такое поведение не предусмотрено языком, соответственно, нужно либо менять часть стандарта, отвечающее за это, что, возможно, поломает чей-то код, либо вводить какой-то дополнительный синтаксис, с помощью которого можно указать, что ваш класс действительно хочет, чтобы компилятор сделал эту работу для ваших операторов.
C++20 добавляет в язык новый оператор <=>, который предоставляет возможность реализовать т.н. "three-way сравнение". Данное сравнение давно представлено в C-функциях на подобии strcmp, которая возвращает значение меньше, равное или большее нуля в зависимости от лексикографического порядка значений аргументов. Для работы данного оператора введена новая механика, работающая для операторов отношения (<, >, <=, >=), приблизительно, следующим образом:
- если пользователь определил свой
<=>, и не определил какие-то операторы сравнения, то при использовании этих операторов, оператор<=>включается в список подходящих функций, причем, включая и обратный порядок операндов. - если пользователь определил свой
<=>, и определил какие-то операторы сравнения, то при использовании этих операторов будут использованы именно предоставленные пользователем перегрузки.
Если в результате разрешения перегрузки был выбран перегруженный оператор <=>, то выражение x @ y, где @ - оператор сравнения, производится по правилу (x <=> y) @ 0, либо по правилу, 0 @ (y <=> x) если порядок аргументов нужно инвертировать.
Разберем на примере перегрузку оператора <=>.
#include <iostream>
#include <compare>
struct Some
{
};
bool operator>(Some const &, int)
{
std::cout << "operator>(Some const &, int)" << std::endl;
return false;
}
std::strong_ordering operator<=>(Some const &, Some const &)
{
std::cout << "operator<=>(Some const &, Some const &)" << std::endl;
return std::strong_ordering::less;
}
std::strong_ordering operator<=>(Some const &, int)
{
std::cout << "operator<=>(Some const &, int)" << std::endl;
return std::strong_ordering::less;
}
int main()
{
Some s1, s2;
s1 < s2; //operator<=>(Some const &, Some const &)
s1 > 2; //operator>(Some const &, int)
s1 < 2; //operator<=>(Some const &, int)
2 < s1; //operator<=>(Some const &, int)
2 > s1; //operator<=>(Some const &, int)
}
Для типа Some предоставлено три оператора сравнения.
s1 < s2 - будет сравниваться с помощью operator<=>(Some const &, Some const &) по правилу (s1 <=> s2) < 0. Результат, естевственно, true, т.к. наши операторы <=> не производят сравнения, а просто всегда считают, что первый аргумент меньше второго (возвращают std::strong_ordering::less).
В выражении s1 > 2 будет использован перегруженный operator>(Some const &, int).
В выражении s1 < 2 будет выбран operator<=>(Some const &, int) и сравнение будет происходить по правилу (s1 <=> 2) < 0.
В выражении 2 < s1 также будет выбран operator<=>(Some const &, int), но для его выбора необходимо инвертировать порядок аргументов и сравнение уже будет происходить по правилу 0 < (s1 <=> 2).
В выражении 2 > s1 также будет выбран operator<=>(Some const &, int) и сравнение будет происходить по правилу 0 > (s1 <=> 2).Заметьте, перегруженный пользователем operator>(Some const &, int) выбран не будет, т.к. для "старых" (two-way comparation) операторов инвертирование порядка аргументов не предусмотрено.
Таким образом, начиная с C++20, в классе достаточно будет перегрузить один оператор <=>, и, используя его, компилятор будет строить код для других сравнений, перегрузки операторов которых пользователь не предоставил.
Также необходимо будет предоставить оператор == для нужного типа аргументов, тогда компилятор будет генерировать на основе == оператор !=.
Подробнее об этом можете почитать на странице https://en.cppreference.com/w/cpp/language/operator_comparison в секции "Three-way comparison".