2010-06-09 16 views
13

tengo una clase con un par de campos numéricos, tales como:operador <en C++

class Class1 { 
    int a; 
    int b; 
    int c; 
public: 
    // constructor and so on... 
    bool operator<(const Class1& other) const; 
}; 

Tengo que utilizar los objetos de esta clase como una llave en una std::map. Por lo tanto, implemento operator<. ¿Cuál es la implementación más simple de operator< para usar aquí?

EDIT: El significado de < puede suponer el fin de garantizar la unicidad, siempre y cuando cualquiera de los campos son desiguales.

EDIT 2:

Una aplicación simplista:

bool Class1::operator<(const Class1& other) const { 
    if(a < other.a) return true; 
    if(a > other.a) return false; 

    if(b < other.b) return true; 
    if(b > other.b) return false; 

    if(c < other.c) return true; 
    if(c > other.c) return false; 

    return false; 
} 

La razón detrás de este post es sólo que he encontrado la implementación anterior demasiado prolijo. Debería haber algo más simple.

+0

Usted debe decidir primero qué '<' significa para el caso en el que varios miembros representan el invariante de la clase. –

Respuesta

4

Depende de si el orden es importante para usted de alguna manera. Si no es así, usted podría hacer esto:

bool operator<(const Class1& other) const 
{ 
    if(a == other.a) 
    { 
     if(b == other.b) 
     { 
      return c < other.c; 
     } 
     else 
     { 
      return b < other.b; 
     } 
    } 
    else 
    { 
     return a < other.a; 
    } 
} 
+0

¡Gracias! Esto es lo que estaba buscando. –

+0

O, por diversión, 'return a! = Other.a? A Skizz

+8

No veo de qué manera esto es mejor que la "implementación simplista" que dio el OP. Esta versión es menos legible. – Frank

28

Supongo que desea implementar ordenamiento lexicográfico.

#include <boost/tuple/tuple.hpp> 
#include <boost/tuple/tuple_comparison.hpp> 
bool Class1::operator<(const Class1& other) const 
{ 
    return boost::tie(a, b, c) < boost::tie(other.a, other.b, other.c); 
} 
+0

¡Agradable! Pero el impulso es demasiado pesado para mi caso particular. –

+0

¡Genial, nunca pensé en usar tuplas! –

+1

@Agnel Kurian: no hay necesidad de "usarlo" más allá de este empate. También es solo encabezado, para minimizar el impacto de la compilación (tiempo/dependencias) puede aislarlo en una unidad de compilación separada (¡pero para compilaciones de versiones, considere hacerlo en el encabezado para alinear!) – sehe

-4

Se podría hacer:

return memcmp (this, &other, sizeof *this) < 0; 

pero que tiene un buen montón de de advertencias - no VTBL por ejemplo, y muchos más, estoy seguro.

+4

Eso casi nunca funcionará como se esperaba. –

+0

@Peter: el OP solo quiere 'garantizar la unicidad siempre que cualquiera de los campos sean desiguales', por lo tanto, al agregar un offsetof para obtener la dirección del primer campo clave y asegurarse de que los campos clave sean contiguos, memcmp debería hacer el truco . – Skizz

15

Creo que hay un malentendido en lo map requiere.

map no requiere que su clase tenga operator< definido. Requiere que se pase un predicado de comparación adecuado, que de manera conveniente se establece en std::less<Key> que usa operator< en el Key.

No debe implementar operator< para colocar su llave en el map. Debe implementarlo solo si lo define para esta clase: es decir, si es significativo.

Se podría definir perfectamente un predicado:

struct Compare: std::binary_function<Key,Key,bool> 
{ 
    bool operator()(const Key& lhs, const Key& rhs) const { ... } 
}; 

Y luego:

typedef std::map<Key,Value,Compare> my_map_t;