Сортировка такого vectorили любого другого применимого (изменяемого входного итератора) диапазона пользовательских объектов типа Xможет быть достигнута с использованием различных методов, особенно включая использование стандартных библиотечных алгоритмов, таких как
Поскольку большинство методов для получения относительного упорядочения Xэлементов уже опубликованы, я начну с некоторых заметок о том, «почему» и «когда» использовать различные подходы.
«Лучший» подход будет зависеть от разных факторов:
- Является ли сортировка диапазонов
Xобъектов общей или редкой задачей (будут ли эти диапазоны сортироваться в нескольких разных местах в программе или пользователями библиотеки)?
- Является ли требуемая сортировка «естественной» (ожидаемой) или существует несколько способов сравнения типа с самим собой?
- Производительность - это проблема, или диапазоны сортировки
Xобъектов должны быть надежными?
Если сортировка диапазонов Xявляется распространенной задачей, и ожидаемая сортировка должна ожидаться (то есть, Xпросто оборачивает одно фундаментальное значение), то, вероятно, будет идти на перегрузкуoperator< так как она позволяет сортировку без какого-либо размытия (например, правильную передачу соответствующих компараторов) и многократно дает ожидаемую полученные результаты.
Если сортировка является распространенной задачей или, вероятно, потребуется в разных контекстах, но есть несколько критериев, которые можно использовать для сортировки Xобъектов, я бы выбрал Functors (перегруженные operator()функции пользовательских классов) или указатели на функции (т.е. один функтор / функция для лексического упорядочения и еще один для естественного упорядочения).
Если сортировка диапазонов типов Xнеобычна или маловероятна в других контекстах, я склонен использовать лямбды вместо того, чтобы загромождать любое пространство имен большим количеством функций или типов.
Это особенно верно, если сортировка не является «чистой» или «естественной» в некотором роде. Вы можете легко понять логику упорядочения, если посмотреть на лямбду, которая применяется на месте, тогда как operator<на первый взгляд она непрозрачна, и вам придется поискать определение, чтобы знать, какая логика упорядочения будет применяться.
Однако обратите внимание, что одно operator<определение - это одна точка отказа, тогда как несколько лямб - это несколько точек отказа и требуют большей осторожности.
Если определение operator< где недоступно, где сортировка выполнена / шаблон сортировки скомпилирован, компилятор может быть вынужден сделать вызов функции при сравнении объектов, вместо того, чтобы включать логику упорядочения, которая может быть серьезным недостатком (по крайней мере, когда оптимизация времени соединения / генерация кода не применяется).
Способы достижения сопоставимости class Xдля использования стандартных алгоритмов сортировки библиотеки
Пусть std::vector<X> vec_X;иstd::vector<Y> vec_Y;
1. Перегрузите T::operator<(T)или operator<(T, T)и используйте стандартные библиотечные шаблоны, которые не ожидают функции сравнения.
Либо элемент перегрузки operator<:
struct X {
int i{};
bool operator<(X const &r) const { return i < r.i; }
};
// ...
std::sort(vec_X.begin(), vec_X.end());
или бесплатно operator<:
struct Y {
int j{};
};
bool operator<(Y const &l, Y const &r) { return l.j < r.j; }
// ...
std::sort(vec_Y.begin(), vec_Y.end());
2. Используйте указатель функции с пользовательской функцией сравнения в качестве параметра функции сортировки.
struct X {
int i{};
};
bool X_less(X const &l, X const &r) { return l.i < r.i; }
// ...
std::sort(vec_X.begin(), vec_X.end(), &X_less);
3. Создайте bool operator()(T, T)перегрузку для пользовательского типа, которая может быть передана как функтор сравнения.
struct X {
int i{};
int j{};
};
struct less_X_i
{
bool operator()(X const &l, X const &r) const { return l.i < r.i; }
};
struct less_X_j
{
bool operator()(X const &l, X const &r) const { return l.j < r.j; }
};
// sort by i
std::sort(vec_X.begin(), vec_X.end(), less_X_i{});
// or sort by j
std::sort(vec_X.begin(), vec_X.end(), less_X_j{});
Эти определения функциональных объектов могут быть написаны немного более обобщенно, используя C ++ 11 и шаблоны:
struct less_i
{
template<class T, class U>
bool operator()(T&& l, U&& r) const { return std::forward<T>(l).i < std::forward<U>(r).i; }
};
который может быть использован для сортировки любого типа с iподдержкой членов <.
4. Передайте анонимное закрытие (лямбда) в качестве параметра сравнения в функции сортировки.
struct X {
int i{}, j{};
};
std::sort(vec_X.begin(), vec_X.end(), [](X const &l, X const &r) { return l.i < r.i; });
Где C ++ 14 обеспечивает еще более общее лямбда-выражение:
std::sort(a.begin(), a.end(), [](auto && l, auto && r) { return l.i < r.i; });
который можно обернуть в макрос
#define COMPARATOR(code) [](auto && l, auto && r) -> bool { return code ; }
сделать обычное создание компаратора довольно плавным:
// sort by i
std::sort(v.begin(), v.end(), COMPARATOR(l.i < r.i));
// sort by j
std::sort(v.begin(), v.end(), COMPARATOR(l.j < r.j));