A classificação de um vectorou qualquer outro intervalo aplicável (iterador de entrada mutável) de objetos personalizados do tipo Xpode ser alcançado usando vários métodos, especialmente incluindo o uso de algoritmos de biblioteca padrão, como
Como a maioria das técnicas, para obter a ordenação relativa dos Xelementos, já foi publicada, começarei com algumas notas sobre "por que" e "quando" para usar as várias abordagens.
A abordagem "melhor" dependerá de diferentes fatores:
- A classificação de intervalos de
Xobjetos é uma tarefa comum ou rara (esses intervalos serão classificados em vários locais diferentes no programa ou pelos usuários da biblioteca)?
- A classificação necessária é "natural" (esperada) ou existem várias maneiras pelas quais o tipo pode ser comparado a si mesmo?
- O desempenho é um problema ou a classificação dos intervalos de
Xobjetos deve ser infalível?
Se a classificação de intervalos Xfor uma tarefa comum e a classificação alcançada for esperada (ou seja, Xapenas agrupar um único valor fundamental), provavelmente a sobrecarga será necessária, operator<uma vez que permite a classificação sem distorção (como passar corretamente os comparadores adequados) e gera repetidamente os resultados esperados resultados.
Se a classificação é uma tarefa comum ou provavelmente requerida em contextos diferentes, mas existem vários critérios que podem ser usados para classificar Xobjetos, eu usaria Functors ( operator()funções sobrecarregadas de classes personalizadas) ou ponteiros de função (ou seja, um functor / função para pedidos lexicais e outro para pedidos naturais).
Se os intervalos de classificação do tipo Xsão incomuns ou improváveis em outros contextos, costumo usar lambdas em vez de sobrecarregar qualquer espaço de nome com mais funções ou tipos.
Isso é especialmente verdadeiro se a classificação não for "clara" ou "natural" de alguma forma. Você pode facilmente obter a lógica por trás da ordem ao olhar para um lambda que é aplicado no local, enquanto que operator<é ofensivo à primeira vista e você precisa procurar a definição para saber qual lógica de ordem será aplicada.
Observe, no entanto, que uma única operator<definição é um único ponto de falha, enquanto várias lambas são múltiplos pontos de falha e requerem mais cautela.
Se a definição de operator<não estiver disponível onde a classificação é feita / o modelo de classificação é compilado, o compilador pode ser forçado a fazer uma chamada de função ao comparar objetos, em vez de incluir a lógica de ordenação, o que pode ser uma desvantagem grave (pelo menos quando otimização do tempo do link / geração de código não é aplicada).
Maneiras de obter comparabilidade class Xpara usar algoritmos de classificação de biblioteca padrão
Deixe std::vector<X> vec_X;estd::vector<Y> vec_Y;
1. Sobrecarregue T::operator<(T)ou operator<(T, T)use modelos de biblioteca padrão que não esperam uma função de comparação.
Qualquer membro de sobrecarga operator<:
struct X {
int i{};
bool operator<(X const &r) const { return i < r.i; }
};
// ...
std::sort(vec_X.begin(), vec_X.end());
ou grátis 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. Use um ponteiro de função com uma função de comparação personalizada como parâmetro da função de classificação.
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. Crie uma bool operator()(T, T)sobrecarga para um tipo personalizado que pode ser passado como função de comparação.
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{});
Essas definições de objeto de função podem ser escritas um pouco mais genéricas usando C ++ 11 e modelos:
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; }
};
que pode ser usado para classificar qualquer tipo com isuporte de membro <.
4. Passe um fechamento anônimo (lambda) como parâmetro de comparação para as funções de classificação.
struct X {
int i{}, j{};
};
std::sort(vec_X.begin(), vec_X.end(), [](X const &l, X const &r) { return l.i < r.i; });
Onde o C ++ 14 permite uma expressão lambda ainda mais genérica:
std::sort(a.begin(), a.end(), [](auto && l, auto && r) { return l.i < r.i; });
que pode ser envolvido em uma macro
#define COMPARATOR(code) [](auto && l, auto && r) -> bool { return code ; }
simplificando a criação de comparadores comuns:
// 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));