Сортування такого 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));