L'ordinamento di tale vector
o qualsiasi altro intervallo di oggetti personalizzati di tipo (mutable input iterator) X
può essere ottenuto utilizzando vari metodi, in particolare l'uso di algoritmi di libreria standard come
Poiché la maggior parte delle tecniche, per ottenere l'ordinamento relativo degli X
elementi, sono già state pubblicate, inizierò con alcune note su "perché" e "quando" per utilizzare i vari approcci.
L'approccio "migliore" dipenderà da diversi fattori:
- L'ordinamento di intervalli di
X
oggetti è un'attività comune o rara (tali intervalli verranno ordinati in più punti diversi nel programma o dagli utenti della biblioteca)?
- L'ordinamento richiesto è "naturale" (previsto) o esistono diversi modi in cui il tipo può essere confrontato con se stesso?
- Le prestazioni sono un problema o gli intervalli di classificazione degli
X
oggetti devono essere infallibili?
Se l'ordinamento di intervalli di X
è un compito comune e ci si aspetta l'ordinamento raggiunto (ovvero X
avvolge solo un singolo valore fondamentale), allora probabilmente andrebbe in sovraccarico operator<
poiché consente l'ordinamento senza alcun fuzz (come il corretto passaggio di comparatori adeguati) e più volte i rendimenti previsti risultati.
Se l'ordinamento è un'attività comune o è probabile che sia richiesta in contesti diversi, ma ci sono più criteri che possono essere utilizzati per ordinare gli X
oggetti, sceglierei Functors ( operator()
funzioni sovraccariche di classi personalizzate) o puntatori a funzioni (ovvero un funzione / funzione per l'ordinamento lessicale e un altro per l'ordinamento naturale).
Se l'ordinamento di intervalli di tipo X
è raro o improbabile in altri contesti, tendo a usare lambdas invece di ingombrare qualsiasi spazio dei nomi con più funzioni o tipi.
Ciò è particolarmente vero se l'ordinamento non è "chiaro" o "naturale" in qualche modo. Puoi facilmente ottenere la logica dietro l'ordinamento quando guardi una lambda che viene applicata sul posto mentre operator<
è opaca a prima vista e dovresti cercare la definizione per sapere quale logica di ordinamento verrà applicata.
Si noti tuttavia che una singola operator<
definizione è un singolo punto di errore mentre più lambas sono più punti di errore e richiedono una maggiore attenzione.
Se la definizione di operator<
non è disponibile dove viene eseguito l'ordinamento / viene compilato il modello di ordinamento, il compilatore potrebbe essere costretto a effettuare una chiamata di funzione durante il confronto di oggetti, invece di allineare la logica di ordinamento che potrebbe essere un grave svantaggio (almeno quando non viene applicata l'ottimizzazione del tempo di collegamento / generazione del codice).
Modi per ottenere la comparabilità di class X
al fine di utilizzare algoritmi di ordinamento delle librerie standard
Let std::vector<X> vec_X;
andstd::vector<Y> vec_Y;
1. Sovraccaricare T::operator<(T)
o operator<(T, T)
utilizzare modelli di libreria standard che non prevedono una funzione di confronto.
O elemento di sovraccarico operator<
:
struct X {
int i{};
bool operator<(X const &r) const { return i < r.i; }
};
// ...
std::sort(vec_X.begin(), vec_X.end());
o gratis 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. Utilizzare un puntatore a funzione con una funzione di confronto personalizzata come parametro della funzione di ordinamento.
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. Creare un bool operator()(T, T)
sovraccarico per un tipo personalizzato che può essere passato come funzione di confronto.
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{});
Queste definizioni di oggetti funzione possono essere scritte un po 'più generiche usando C ++ 11 e modelli:
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; }
};
che può essere utilizzato per ordinare qualsiasi tipo con i
supporto membro <
.
4. Passare una chiusura anonima (lambda) come parametro di confronto alle funzioni di ordinamento.
struct X {
int i{}, j{};
};
std::sort(vec_X.begin(), vec_X.end(), [](X const &l, X const &r) { return l.i < r.i; });
Dove C ++ 14 abilita un'espressione lambda ancora più generica:
std::sort(a.begin(), a.end(), [](auto && l, auto && r) { return l.i < r.i; });
che potrebbe essere racchiuso in una macro
#define COMPARATOR(code) [](auto && l, auto && r) -> bool { return code ; }
rendendo abbastanza ordinaria la creazione di comparatori:
// 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));