2010-10-30 7 views
5

Überprüfen Sie den folgenden Code ein:Mit Komparator für STL eingestellt

string toLowerCase(const string& str) { 
    string res(str); 
    int i; 

    for (i = 0; i < (int) res.size(); i++) 
     res[i] = (char) tolower(res[i]); 

    return res; 
} 

class LeagueComparator 
{ 
public: 
    bool operator()(const string& s1, const string& s2) 
    { 
     return toLowerCase(s1) < toLowerCase(s2); 
    } 
}; 

int main() 
{ 
    set<string, LeagueComparator> leagues; 
    set<string, LeagueComparator>::iterator iter; 

    leagues.insert("BLeague"); 
    leagues.insert("aLeague"); // leagues = {"aLeague", "BLeague"} 
    leagues.insert("ALeague"); 

    for (iter = leagues.begin(); iter != leagues.end(); iter++) 
     cout << *iter << endl; 

    return 0; 
} 

Die Ausgabe lautet:

aLeague 
BLeague 

die mir schockierend ist. Ich dachte (und erwartete) die Ausgabe wäre:

aLeague 
ALeague 
BLeague 

Vor der Ausführung von leagues.insert("ALeague");, die leagues enthält "aLeague" und "BLeague". Meine Frage ist, während der Ausführung leagues.insert("ALeague");, warum die Maschine behandelt "ALeague" == "aleague"? Nach meinem Verständnis gibt es kein Element "ALeague" in leagues. So sollte "ALeague" in leagues eingefügt werden. Der Vergleicher sollte bestimmen, wo "ALeague" zu setzen ist.

Vielen Dank im Voraus.

PS: Bitte schlagen Sie mich nicht für die Verwendung von C-Style-Cast. : P Ich bin zu faul, um static_cast einzugeben.

+0

Die Tatsache, dass es sich anfühlt Sie eine C++ Casts ist eines der Hauptgrund, C++ Casts existieren arbeiten müssen auszuführen - nämlich, dass Sie jede Art von Gießen vermeiden sollten in C++. In diesem Fall sollten Sie die Würfe vollständig entfernen und stattdessen die richtigen Typen verwenden. I.e. anstelle von '(int) res.size()', entferne den Cast und ändere 'i's Type in' unsigned'. –

+0

Außerdem sollte 'i' in der Schleife deklariert werden, nicht außerhalb der Schleife. Und in C++ sollte toLowerCase wahrscheinlich einfach 'std :: transform (str.begin(), str.end(), str.begin(), std :: ptr_fun (tolower))' aufrufen, anstatt eine explizite Schleife zu schreiben. –

+0

@Billy ONeal: Danke.Ich muss verwendet werden, um 'transform()' zu verwenden. das 'toLowerCase' wurde vor vielen Jahren von mir geschrieben. Ich glaube, ich wusste zu dieser Zeit noch nichts von 'transform '. Ich werde meine Codebasis aktualisieren. – Donotalo

Antwort

14

Ihr Komparator, dank der toLowerCase, sagt, dass "aLeague" == "ALeague". Da (entsprechend Ihrer Vergleichszahl) "aLeague" < "ALeague" == false und "ALeague" < "aLeague" == false müssen sie gleichwertig sein. Und das Einfügen eines äquivalenten Elements in eine Menge tut nichts.

+3

+1. Beachten Sie, dass der Komparator keine Gleichheit herstellt, sondern Gleichwertigkeit herstellt. Es gibt einen Unterschied w.r.t. Standard- und STL-Dokumentation. –

+0

Danke, meinen Post redigieren. –

3

Angesichts der Komparator, die Sie zur Verfügung gestellt, "ALEague" ist in der Tat äquivalent "aLeague".

zwei Werte angegeben, x und y, und eine weniger-als-Komparator z:

  • Wenn z (x, y) wahr ist, dann ist x kleiner als y
  • Wenn z (y, x) ist wahr, dann ist y kleiner als x
  • Wenn keine der beiden wahr ist, dann ist x äquivalent zu y
  • Wenn beide wahr sind, dann haben Sie einen gebrochenen Komparator.
+0

+1, aber ein kleines Problem mit der dritten Kugel w.r.t. STL-Dokumente Es gibt einen Unterschied zwischen Gleichheit und Äquivalenz. Ein Kleiner-als-Komparator kann keine Gleichheit, nur Äquivalenz herstellen. –

+0

@Billy ONeal: Was sind die Definitionen von "Gleichheit" und "Äquivalenz" laut STL doc (ich habe es nicht)? – Donotalo

+0

@ Donotalo: Gleichheit ist ein Vergleich mit einem Gleichheitsvergleich, oder 'operator =='. Äquivalenz ist der Zustand, in dem ein Kleiner-als-Vergleicher oder 'Operator <' für die Reihenfolge der Argumente, wie hier angegeben, false zurückgibt. Konzeptionell ist es der Unterschied zwischen [Gleichheit vergleichbar] (http://www.sgi.com/tech/stl/EqualityComparable.html) und [weniger als vergleichbar] (http://www.sgi.com/tech/stl/ LessThanComparable.html). –

4

Wenn Sie einen Wert in eine Menge einfügen, überprüft das Objekt, ob es bereits diesen Wert enthält. Ihr Objekt LeagueComparator vergleicht ALeague mit den anderen beiden bereits im Set enthaltenen Werten. Es stellt fest, dass der vorhandene Wert aLeague weder größer noch kleiner als der vorgeschlagene neue Eintrag (ALeague) ist, also müssen sie gleich sein, und daher wird nicht mit dem Einfügen fortgefahren. Das Set bleibt mit nur zwei Elementen bestehen. Das ist der Kernpunkt der Bereitstellung eines Kundenvergleichsobjekts, damit Sie steuern können, wie der Satz bestimmt, ob zwei Elemente übereinstimmen.

+0

+1. Beachten Sie, dass die meisten Verwendungen von "gleich" hier durch "äquivalent" ersetzt werden sollten, um mit STL-Dokumenten konsistent zu sein. Kleiner als Komparatoren können keine Gleichheit herstellen. –

0

Ersetzen Sie Ihre LeagueComparator mit

class LeagueComparator 
{ 
public: 
    bool operator()(const string& s1, const string& s2) 
    { 
     return toLowerCase(s1) < toLowerCase(s2) || 
       !(toLowerCase(s2) < toLowerCase(s1)) && s1 < s2; 
    } 
}; 
+0

Das entspricht der Angabe von überhaupt keinem Vergleich. Ihr Komparator gibt in allen Fällen einfach 's1

+0

Es ist nicht wahr. 's1 =" b "', 's2 =" A "'. Mein Komparator gibt 'false' wegen' false || zurück ! true && true = false'. 's1