Нет, C ++ не пишет эти операторы для вас.
Если вы думаете, что это отстой, вы правы. Множество способов сделать так, чтобы это сосало меньше, уже сделано. Я расскажу о 4 из них.
В c ++ 20 , если вы правильно напишите operator<=>
( 3-way оператор "космического корабля") или =default
it тогда для вас будут написаны все <
, <=
, >=
, >
, !=
и ==
.
struct bob {
int x,y;
auto operator<=>( bob const& )const = default;
};
В приведенном выше bob
каждый оператор <
==
и т. Д. Написан для него на C ++.
Просто напишите их
До c ++ 20 вы должны написать все из них, если хотите их все. Это утомительно и подвержено ошибкам.
Использование std::tie
и вызов <
и т.п. для них немного менее подвержены ошибкам:
struct bob {
int x, y;
friend bool operator<( bob const& lhs, bob const& rhs ) {
return std::tie(lhs.x, lhs.y) < std::tie(rhs.x, rhs.y);
}
};
или даже
struct bob {
int x, y;
friend auto as_tie( bob const& b ) { // C++14
return std::tie(b.x, b.y);
}
friend bool operator<( bob const& lhs, bob const& rhs ) {
return as_tie(lhs) < as_tie(rhs);
}
};
потому что tuple
делает правильное лексографическое сравнение; написание лексографических сравнений без ошибок раздражает.
Метапрограмма вашего обхода
При сравнении строк вы обычно используете strcmp
. Возвращает отрицательное число, если меньше, положительное число, если оно больше, и 0, если оно равно. Этот шаблон может быть более эффективным, чем повторное выполнение <
или ==
.
Создание одной strcmp
подобной функции приводит к <
==
, и могут быть выполнены другие операции сравнения:
namespace utils {
template<class D>
struct use_cmp {
friend bool operator<( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) < 0;
}
friend bool operator>( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) > 0;
}
friend bool operator<=( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) <= 0;
}
friend bool operator>=( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) >= 0;
}
friend bool operator==( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) == 0;
}
friend bool operator!=( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) != 0;
}
private:
D const& self() const { return *static_cast<D const*>(this); }
};
}
Теперь у нас есть тип:
struct bob {
int x, y;
};
и мы хотим иметь возможность использовать операторы сравнения на нем:
struct bob : utils::use_cmp<bob>
{
int x, y;
bob( int x_, int y_ ):x(x_), y(y_) {} // constructor
friend int cmp( bob const& lhs, bob const& rhs ) {
if (lhs.x < rhs.x) return -1;
if (lhs.x > rhs.x) return 1;
if (lhs.y < rhs.y) return -1;
if (lhs.y > rhs.y) return 1;
return 0;
}
};
и использование магии CRTP bob
теперь имеет каждый оператор сравнения, написанный для него.
Живой пример .
Это надоедливое friend int cmp
(что раздражает, чем больше у вас в нем участников) может быть обработано еще большим вспомогательным кодом:
namespace utils {
template<class...Ts>
int cmp( std::tuple<Ts...> const& lhs, std::tuple<Ts...> const& rhs );
template<class T, class...LowPriority>
int cmp( T const& lhs, T const& rhs, LowPriority&&... );
template<class...Ts, std::size_t...Is>
int tuple_cmp( std::tuple<Ts...> const& lhs, std::tuple<Ts...> const& rhs, std::index_sequence<Is...> ) {
int result = 0;
( (result = cmp( std::get<Is>(lhs), std::get<Is>(rhs) )) && ... );
return result;
}
template<class...Ts>
int cmp( std::tuple<Ts...> const& lhs, std::tuple<Ts...> const& rhs ) {
return tuple_cmp( lhs, rhs, std::make_index_sequence<sizeof...(Ts)>{} );
}
template<class T, class...LowPriority>
int cmp( T const& lhs, T const& rhs, LowPriority&&... ) {
if (lhs < rhs) return -1;
if (rhs < lhs) return 1;
return 0;
}
}
, который еще более загадочный код, но вы получаете более простой bob
:
struct bob : utils::use_cmp<bob>
{
int x, y;
bob( int x_, int y_ ):x(x_), y(y_) {}
friend auto as_tie(bob const& b) {
return std::tie(b.x,b.y);
}
friend int cmp( bob const& lhs, bob const& rhs ) {
return utils::cmp( as_tie(lhs), as_tie(rhs) );
}
};
Обратите внимание, однако, что все это сделано и лучше на operator<=>
в c ++ 20 .
Живой пример .
Воспользуйтесь чужим решением
Это похоже на подход, который boost :: operator использует для написания этих операторов для вас.