Wie kann ich std::maps mit benutzerdefinierten Typen als Schlüssel verwenden?
Lesezeit: 1 Minute
Unbekannt
Ich frage mich, warum ich STL-Maps nicht mit benutzerdefinierten Klassen verwenden kann. Wenn ich den folgenden Code kompiliere, erhalte ich die folgende kryptische Fehlermeldung. Was heißt das? Warum passiert es auch nur mit benutzerdefinierten Typen? (Primitive Typen sind in Ordnung, wenn sie als Schlüssel verwendet werden.)
C:\Benutzer\Admin\Dokumente\dev\sandbox\sandbox\sandbox.cpp|24|von hier aus instanziiert|
C:\MinGW\bin..\lib\gcc\mingw32\3.4.5……..\include\c++\3.4.5\bits\stl_function.h|227|error: no match for ‘operator <' in '__x < __y'| ||=== Bau abgeschlossen: 1 Fehler, 0 Warnungen ===|
#include <iostream>
#include <map>
using namespace std;
class Class1
{
public:
Class1(int id);
private:
int id;
};
Class1::Class1(int id): id(id)
{}
int main()
{
Class1 c1(1);
map< Class1 , int> c2int;
c2int[c1] = 12;
return 0;
}
Mögliches Duplikat von C++ unordered_map mit einem benutzerdefinierten Klassentyp als Schlüssel
– Ciro Santilli Путлер Капут 六四事
18. April 2019 um 20:17 Uhr
Pavel Minaev
Du nicht verfügen über definieren operator< eigentlich für deine Klasse. Sie können auch eine Komparatorfunktionsobjektklasse dafür erstellen und diese zum Spezialisieren verwenden std::map. Um dein Beispiel zu erweitern:
Es passiert einfach so, dass die Voreinstellung für den dritten Template-Parameter von std::map ist std::lessdie an delegieren wird operator< für Ihre Klasse definiert (und schlagen fehl, wenn es keine gibt). Aber manchmal möchten Sie, dass Objekte als Kartenschlüssel verwendet werden können, aber Sie haben eigentlich keine sinnvoll Vergleichssemantik, und deshalb möchten Sie die Leute nicht verwirren, indem Sie angeben operator< in deiner Klasse nur dafür. Wenn das der Fall ist, können Sie den obigen Trick anwenden.
Eine weitere Möglichkeit, dasselbe zu erreichen, ist die Spezialisierung std::less:
Das hat den Vorteil, dass es abgeholt wird std::map “standardmäßig”, und doch belichten Sie nicht operator< andernfalls zum Client-Code.
Ich würde vorschlagen, den beiden Funktionen ein const-Schlüsselwort hinzuzufügen.
– Diomidis spinellis
28. August 2010 um 12:41 Uhr
vielleicht lohnt es sich friend mit dem struct less sonst sehe ich es als eine kompromittierte Kapselung.
– Skywalker
3. Oktober 2012 um 14:52 Uhr
Die Schablonenstruktur sollte mit einem Semikolon abgeschlossen werden, andernfalls erhalten Sie Kompilierungsfehler. Leider konnte ich dies aufgrund der geringen Anzahl geänderter Charaktere nicht mit einem Edit beheben
– Ident
26. Juli 2015 um 22:09 Uhr
Aber warum setzen Sie struct less info std?
– Wladimir Zyschnati
18. Juli 2016 um 11:58 Uhr
Es ist schon drin std. Das ist nur eine Spezialisierung davon.
– Pavel Minaev
18. Juli 2016 um 18:02 Uhr
GManNickG
Standardmäßig std::map (und std::set) verwenden operator< Sortierung zu bestimmen. Daher müssen Sie definieren operator< auf deine Klasse.
Es werden zwei Objekte betrachtet gleichwertigif !(a < b) && !(b < a).
Wenn Sie aus irgendeinem Grund einen anderen Komparator verwenden möchten, wird das dritte Vorlagenargument der map kann geändert werden, zu std::greaterzum Beispiel.
Tatsächlich können Sie den Komparator in fast jede Funktion mit zwei Argumenten ändern.
– xtofl
9. Juli 2009 um 10:07 Uhr
aJ.
Sie müssen definieren operator < für die Klasse1.
Map muss die Werte mit dem Operator < vergleichen und daher müssen Sie dasselbe angeben, wenn benutzerdefinierte Klassen als Schlüssel verwendet werden.
class Class1
{
public:
Class1(int id);
bool operator <(const Class1& rhs) const
{
return id < rhs.id;
}
private:
int id;
};
Es braucht keinen operator< ; es ist lediglich standardmäßig darauf eingestellt. Siehe die Antwort von GMan oder Pavel.
Schlüssel müssen vergleichbar sein, aber Sie haben keinen passenden definiert operator< für Ihre benutzerdefinierte Klasse.
Ich möchte ein wenig erweitern Pavel Minaevs Antwort, die Sie lesen sollten, bevor Sie meine Antwort lesen. Beide von Pavel vorgestellten Lösungen werden nicht kompiliert, wenn das zu vergleichende Element (wie z id im Code der Frage) ist privat. In diesem Fall wirft VS2013 den folgenden Fehler für mich:
Fehler C2248: „Class1::id“: Zugriff auf privates Mitglied, das in Klasse „Class1“ deklariert ist, nicht möglich
Wie von erwähnt SkyWalker in den Kommentaren zu Pavels Antwort mit a friend Deklaration hilft. Wenn Sie sich über die korrekte Syntax wundern, hier ist sie:
class Class1
{
public:
Class1(int id) : id(id) {}
private:
int id;
friend struct Class1Compare; // Use this for Pavel's first solution.
friend struct std::less<Class1>; // Use this for Pavel's second solution.
};
Wenn Sie jedoch beispielsweise eine Zugangsfunktion für Ihr privates Mitglied haben getId() zum idwie folgt:
class Class1
{
public:
Class1(int id) : id(id) {}
int getId() const { return id; }
private:
int id;
};
dann können Sie es anstelle von a verwenden friend Deklaration (d. h. Sie vergleichen lhs.getId() < rhs.getId()). Seit C++11Sie können auch a verwenden Lambda-Ausdruck zum Pavels erste Lösung, anstatt eine Komparatorfunktionsobjektklasse zu definieren. Alles zusammengenommen könnte der Code wie folgt geschrieben werden:
Mögliches Duplikat von C++ unordered_map mit einem benutzerdefinierten Klassentyp als Schlüssel
– Ciro Santilli Путлер Капут 六四事
18. April 2019 um 20:17 Uhr