2011-04-26 9 views
7

tente actuellement de trier un vecteur d'objet, chaque objet contenant une chaîne, en C++Surcharger opérateur comparision dans les résultats en C + « opérateur invalide < »

Les chaînes peuvent contenir des lettres ou des chiffres (en raison d'une contrainte de conception , ceci est nécessaire, car le comparateur peut être changé).

Pour l'instant, la classe de l'objet est surchargée, de sorte que lorsque deux objets sont comparés, les chaînes qu'ils contiennent sont comparées. Cela fonctionne à un certain point - cependant, quand j'utilise une opération de tri (comme le tri STL) pour mettre les objets dans l'ordre, il va trier trois chaînes telles que "1", "4", "12", dans l'ordre "1", "12", "4". 4 est supérieur à 12, mais parce qu'il commence à se comparer à partir du chiffre le plus à gauche, ce type "incorrect" se produit.

Ma première réaction a été de changer la façon dont je surchargeais l'opération de comparaison. Je voudrais d'abord vérifier la longueur de la chaîne que je comparais - ce qui serait un signe révélateur si le contenu de la chaîne était plus grand ou plus petit.

// 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); 
} 

Cette opération se traduit par un message: lors de l'exécution "Expression opérateur invalide <".

Des idées sur l'endroit où je fais une erreur? Il semble que je devrais être capable de dicter à l'opération exactement comment je veux que l'opération de tri se produise - même si elle est invalide, puisque j'utilise actuellement un vecteur pour contenir les objets.

lors de l'initialisation de Comparator l'objet 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

Qu'est-ce comparateur? Postez le code pour cela. –

+0

pouvez-vous s'il vous plaît montrer la définition de comparateur? –

+0

@Mike et @Mario - le comparateur est initialisé lors de l'initialisation d'un objet nodeRecord. Vous pouvez voir ceci ci-dessus. – BSchlinker

Répondre

10

Votre opérateur est effectivement invalide.

L'opérateur < doit posséder un certain nombre de propriétés mathématiques si vous souhaitez qu'il soit utilisable pour le tri. L'une est la propriété antisymétrie:

x < y => !(y < x)

Définissons x = "b" et y = "aa".

  • x < y parce que la longueur de "b" est inférieure à la longueur de "aa"
  • y < x parce "aa" est inférieure à "b"

Hum?

Notez également que votre définition est bizarre pour les nombres au cas où ils sont préfixés par 0 s. Oh, et la comparaison des chaînes est beaucoup plus lente que la comparaison des nombres.

Ma prise? Arrêtez de modifier le nœud avec des informations de comparaison. Le mode de comparaison réel n'a rien à faire dans le nœud lui-même.

Ensuite, vous allez simplement écrire deux méthodes de comparaison, l'une qui compare par le coût et l'autre par origine.


Et pour revenir à la question initiale, comment écrire un comparateur qui considèrent ["a", "b", "aa"] triés?

Vous étiez presque là, mais la comparaison de "longueur" est incomplète. Vous devez revenir à la comparaison lexicale réelle seulement dans le cas où les longueurs diffèrent, ainsi vous avez oublié le cas où la longueur de l'argument de droite est inférieure à celle de gauche.

Ainsi, la forme correcte est, en supposant deux cordes:

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

Merci! Votre solution m'a vraiment aidé à découvrir et à comprendre le problème. et m'a rappelé un autre cas que j'avais oublié. – BSchlinker

0

Pourquoi ne pas utiliser un seul comparateur et faire de cette fonction un peu plus intelligent? Faites-le vérifier les caractères numériques au début, si c'est le cas, faites une paire de strtol() ou atoi() et comparez les résultats.

Sinon, comparez la longueur de la chaîne et les caractères selon vos besoins non numériques.

+0

Je veux être capable de trier les chaînes de la même façon que je trier des nombres. Par exemple, les piqûres "a", "aa" et "b" doivent être triées "a", "b", "aa". La méthode que j'ai posté est la seule méthode que je connaisse qui me permettra d'accomplir ceci. – BSchlinker

+0

@BSchlinker: mis à jour ma réponse. – wallyk

+0

Malheureusement, cela ne résoudra pas mon problème. La même erreur se produira = ( – BSchlinker

1

J'ai trouvé le segment de code suivant qui lançait l'erreur, puis j'ai réfléchi au fonctionnement de mon opération surchargée.

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); 
    } 

solution de travail est ce (modifié à nouveau grâce aux commentaires laissés par 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); 
} 

Merci à tous ceux qui ont aidé!