La clasificación de tal vectoro cualquier otro rango aplicable (iterador de entrada mutable) de objetos de tipo personalizados Xse puede lograr usando varios métodos, especialmente incluyendo el uso de algoritmos de biblioteca estándar como
Como la mayoría de las técnicas, para obtener un orden relativo de X elementos, ya se han publicado, comenzaré con algunas notas sobre "por qué" y "cuándo" usar los diversos enfoques.
El "mejor" enfoque dependerá de diferentes factores:
- ¿La clasificación de rangos de
Xobjetos es una tarea común o rara (se ordenarán dichos rangos en diferentes lugares del programa o por los usuarios de la biblioteca)?
- ¿La clasificación requerida es "natural" (esperada) o hay varias formas en que el tipo podría compararse a sí mismo?
- ¿El rendimiento es un problema o la clasificación de los rangos de
Xobjetos debe ser infalible?
Si la ordenación de los rangos de Xes una tarea común y es de esperar la ordenación lograda (es decir, Xsimplemente envuelve un único valor fundamental), entonces probablemente iría por sobrecargaoperator< ya que permite la clasificación sin ninguna confusión (como pasar correctamente los comparadores adecuados) y produce repetidamente los resultados esperados resultados.
Si ordenar es una tarea común o es probable que se requiera en diferentes contextos, pero hay varios criterios que se pueden usar para ordenar Xobjetos, elegiría Functors ( operator()funciones sobrecargadas de clases personalizadas) o punteros de función (es decir, un functor / función para ordenamiento léxico y otro para ordenamiento natural).
Si ordena rangos de tipo X es poco común o poco probable en otros contextos, tiendo a usar lambdas en lugar de saturar cualquier espacio de nombres con más funciones o tipos.
Esto es especialmente cierto si la clasificación no es "clara" o "natural" de alguna manera. Puede obtener fácilmente la lógica detrás del pedido cuando mira una lambda que se aplica en el lugar, mientras que operator<es opaca a primera vista y tendría que buscar la definición para saber qué lógica de pedido se aplicará.
Sin embargo, operator<tenga en cuenta que una sola definición es un único punto de falla, mientras que múltiples lambas son múltiples puntos de falla y requieren más precaución.
Si la definición de operator< no está disponible donde se realiza la ordenación / se compila la plantilla de ordenación, el compilador podría verse obligado a realizar una llamada a la función al comparar objetos, en lugar de incluir la lógica de ordenación que podría ser un inconveniente grave (al menos cuando La optimización del tiempo de enlace / generación de código no se aplica).
Formas de lograr comparabilidad class Xpara utilizar algoritmos de clasificación de bibliotecas estándar
Dejar std::vector<X> vec_X;ystd::vector<Y> vec_Y;
1. Sobrecargue T::operator<(T)o operator<(T, T)use plantillas de biblioteca estándar que no esperen una función de comparación.
Cualquiera de los miembros 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());
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. Utilice un puntero de función con una función de comparación personalizada como parámetro de función de clasificación.
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. Cree una bool operator()(T, T)sobrecarga para un tipo personalizado que se puede pasar como functor de comparación.
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{});
Esas definiciones de objetos de función se pueden escribir un poco más genéricas usando C ++ 11 y plantillas:
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 se puede usar para ordenar cualquier tipo con isoporte de miembros <.
4. Pase un cierre anónimo (lambda) como parámetro de comparación a las funciones de clasificación.
struct X {
int i{}, j{};
};
std::sort(vec_X.begin(), vec_X.end(), [](X const &l, X const &r) { return l.i < r.i; });
Donde C ++ 14 permite una expresión lambda aún más genérica:
std::sort(a.begin(), a.end(), [](auto && l, auto && r) { return l.i < r.i; });
que podría estar envuelto en una macro
#define COMPARATOR(code) [](auto && l, auto && r) -> bool { return code ; }
haciendo que la creación de comparadores ordinarios sea bastante fluida:
// 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));