¿Por qué la función de comparación STL no es miembro?
-
06-07-2019 - |
Pregunta
Por curiosidad, ¿por qué la función de comparación para stl :: sort no puede ser un miembro estático?
Tengo un pequeño foo de clase auxiliar que se declara y define en un encabezado, pero ahora tengo que crear un archivo foo.cpp para la implementación de cmp () para que no se defina de forma múltiple.
También tengo que pensar en un nombre adecuadamente decorado para que fooCmp () no choque con ningún otro cmp ().
Debido a que no tiene acceso a ninguna variable miembro, cualquier operación de comparación que necesite acceso a algún otro valor (por ejemplo, ordenar por distancia desde foo.bar) necesita la compleja llamada bind2nd call.
Solución
No estoy seguro de qué se queja:
std::sort(begin,end) // use operator<
std::sort(begin,end,order) // Where order is a functor
Entonces el orden puede ser:
- Una función
- Una función miembro estática
- O un objeto que se comporta como una función.
Lo siguiente funciona para mí:
class X
{
public: static bool diff(X const& lhs,X const& rhs) { return true;}
};
int main()
{
std::vector<X> a;
std::sort(a.begin(),a.end(),&X::diff);
}
Pero si la clase tiene un orden natural, ¿por qué no simplemente definir el operador < para la clase. Esto le permitirá el acceso a los miembros y se comportará bien para la mayoría de los contenedores / algoritmos estándar que necesitan definir un pedido.
class X
{
public: bool operator<(X const& rhs) const { return true;}
};
int main()
{
std::vector<X> a;
std::sort(a.begin(),a.end());
}
Otros consejos
Si le preocupa una función de comparación definida de forma múltiple, intente declarar la función con un enlace static
. Entonces, el alcance de la función no se extiende más allá de la unidad de compilación donde se encuentra.
Dicho esto, su comparación " function " no es necesario que sea una función, sino que puede ser una función objeto . Un objeto de función es muy parecido a una función pero se implementa como un operator()
que toma los parámetros apropiados dentro de una clase regular. Como es una clase regular, puede pasar parámetros de constructor a la clase.
Aquí hay un ejemplo simple:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class comparator {
public:
bool operator()(int a, int b) {
return a < b;
}
};
int main(int, char *[])
{
vector<int> a;
a.push_back(1);
a.push_back(3);
a.push_back(2);
sort(a.begin(), a.end(), comparator());
cout << a << endl;
}
en realidad suena como si la función fuera declarado en la clase, definido en el encabezado pero fuera de la clase sin vinculación en línea
es decir, algo como:
class foo{
public:
static bool compare(const foo& lhs,const foo& rhs);
...
};
bool foo::compare(const foo& lhs,const foo& rhs){
...
}
en lugar de
class foo{
public:
static bool compare(const foo& lhs,const foo& rhs);
...
};
inline bool foo::compare(const foo& lhs,const foo& rhs){
...
}
el primero de los cuales hará que la función se defina en cada unidad de compilación que
#includes "foo.h"