2011-04-26 20 views
7

Actualmente intentar ordenar un vector de objeto, con cada objeto que contiene una cadena, en C++sobrecarga de operadores comparación en los resultados de C++ en "operador no válido <"

Las cadenas pueden contener letras o números (debido a una restricción de diseño , esto es necesario, ya que el comparador puede ser cambiado).

En este momento, la clase del objeto está sobrecargada, de modo que cuando se comparan dos objetos, se comparan las cadenas que contienen. Esto funciona hasta cierto punto; sin embargo, cuando uso una operación de clasificación (como STL sort) para ordenar los objetos, ordenará tres cadenas como "1", "4", "12", en el orden "1", "12", "4". 4 es mayor que 12, pero debido a que comienza comparando desde el dígito más a la izquierda, esta clasificación 'incorrecta' ocurre.

Mi respuesta inicial fue cambiar la forma en que estaba sobrecargando la operación de comparación. Primero verificaría la longitud de la cuerda que estaba comparando, lo que sería una señal reveladora si el contenido de la cuerda fuera más grande o más pequeño.

// overloaded comparision operators 
friend bool operator<(const nodeRecord & record1, const nodeRecord & record2){ 
    // we need to deal with strings of different lengths... 
    if(record1.comparator.length() < record2.comparator.length()) 
     return true; 
    else 
     return (record1.comparator < record2.comparator); 
} 

estos resultados de operación en una "expresión: Operador no válido <" de mensajes en tiempo de ejecución.

¿Alguna idea de dónde estoy cometiendo un error? Parece que debería ser capaz de dictar a la operación exactamente cómo quiero que ocurra la operación de clasificación, incluso si no es válida, ya que actualmente estoy usando un vector para contener los objetos.

Comparador durante la inicialización del objeto nodeRecord:

nodeRecord(int fromNode, int toNode, int connectionCost, bool compareByCost = false){ 
    // take the provided stock information and insert it into the object 
    stringstream fromNodeSS; 
    fromNodeSS << fromNode; 
    this->fromNode = fromNodeSS.str(); 
    stringstream toNodeSS; 
    toNodeSS << toNode; 
    this->toNode = toNodeSS.str(); 
    this->connectionCost = connectionCost; 

    // set the comparator to our chosen comparision term 
    if (!compareByCost){ 
     this->comparator = this->fromNode; // we use from node in this case, since we build the tree outwards 
    } 
    else{ 
     stringstream ss; 
     ss << this->connectionCost; 
     this->comparator = ss.str(); // we use the connection cost in this case, to allow us to sort new connections 
    } 

    // set this as a non-null (active) record 
    this->nullRecord = false; 
} 
+0

¿Cuál es comparador? Publica el código para eso. –

+0

¿puede mostrar la definición de comparador? –

+0

@Mike y @Mario: el comparador se inicializa durante la inicialización de un objeto nodeRecord. Puedes ver esto arriba. – BSchlinker

Respuesta

10

Su operador no es válido.

El operador < debe tener una serie de propiedades matemáticas si desea que se pueda utilizar para la clasificación. Una de ellas es la propiedad ANTISIMETRÍA:

x < y => !(y < x)

Definamos x = "b" y y = "aa".

  • x < y porque la longitud de "b" es inferior a la longitud de "aa"
  • y < x"aa" porque es inferior a "b"

Hum?

También tenga en cuenta que su definición es rara para los números en caso de que estén prefijados por 0 s.

Ah, y la comparación de cadenas es mucho más lenta que la comparación de números.

Mi opinión? Deje de alterar el nodo con información de comparación. El modo de comparación real no tiene nada que ver dentro del nodo en sí.

Luego, solo tendrá que escribir dos métodos de comparación, uno que se compara por costo y el otro por origen.


Y para volver al tema original, la forma de escribir un comparador que consideran ["a", "b", "aa"] ordenados?

Ya casi llegó, pero la comparación de "longitud" es incompleta. Debe retroceder a la comparación léxica real solo en el caso de que las longitudes difieran, por lo tanto, se olvidó del caso en que la longitud del argumento del lado derecho es inferior a la del lado izquierdo.

Así, la forma correcta es decir, suponiendo dos cadenas:

bool compare(std::string const& lhs, std::string const& rhs) { 
    if (lhs.length() < rhs.length()) { return true; } 
    if (rhs.length() < lhs.length()) { return false; } // don't forget this 
    return lhs < rhs; 
} 
+0

¡Gracias! Su solución realmente me ayudó a descubrir y comprender cuál era el problema y me recordó sobre otro caso que había olvidado. – BSchlinker

0

¿Por qué no utilizar un único comparador y hacer que la función de un poco más inteligente? Haga que compruebe si hay caracteres numéricos al principio, de ser así, haga un par de strtol() o atoi() y compare los resultados.

De lo contrario, compare la longitud de la cadena y los caracteres según sus requisitos no numéricos.

+0

Quiero ser capaz de ordenar cadenas de manera similar a cómo clasifico los números. Por ejemplo, las picaduras "a", "aa" y "b" se deben clasificar "a", "b", "aa". El método que he publicado es el único método que conozco que me permitirá lograr esto. – BSchlinker

+0

@BSchlinker: actualicé mi respuesta. – wallyk

+0

Desafortunadamente, esto no resolverá mi problema. Se producirá el mismo error = ( – BSchlinker

1

Encontré el siguiente segmento de código que arrojaba el error, luego pensé en cómo estaba funcionando mi operación sobrecargada.

template<class _Ty1, class _Ty2> inline 
    bool _Debug_lt(_Ty1& _Left, _Ty2& _Right, 
     _Dbfile_t _File, _Dbline_t _Line) 
    { // test if _Left < _Right and operator< is strict weak ordering 
    if (!(_Left < _Right)) 
     return (false); 
    else if (_Right < _Left) 
     _DEBUG_ERROR2("invalid operator<", _File, _Line); 
    return (true); 
    } 

Solución de trabajo es la siguiente (modificado de nuevo gracias a los comentarios dejados por Matthieu M.)

// overloaded comparision operators 
friend bool operator<(const nodeRecord & record1, const nodeRecord & record2){ 
    // we need to deal with strings of different lengths... 
    if(record1.comparator.length() > record2.comparator.length() 
     && (record1.comparator.length() !=0 && record2.comparator.length() != 0)) 
     return false; 
    else if(record1.comparator.length() < record2.comparator.length() 
     && (record1.comparator.length() !=0 && record2.comparator.length() != 0)) 
     return true; 
    else 
     return (record1.comparator < record2.comparator); 
} 

Gracias a todos los que ayudaron!