std::map mit eigener Klasse als Schlüssel
-
Hallo,
ich wollte eine std::map erstellen, die als Schlüssel eine von mir
geschriebene Klasse benutzt. Die Klasse stellt einen dreidimensionale
Koordinate dar und heißt Point, mit x, y und z als Member.Ich definiere mir also in einer anderen Header-Datei eine map:
std::map<Point, Vec3f> data;und wenn ich dann in der dazugehörigen *.cpp-Datei mit folgendem
this->data[Point(x,y,z)] = Vec3f(vx,vy,vz);auf den Member data zugreifen will, verschluckt sich der Compiler:
error C2678: Binärer Operator '<': Es konnte kein Operator gefunden werden, der einen linksseitigen Operanden vom Typ 'const vc::Point' akzeptiert (oder keine geeignete Konvertierung möglich)
(VS2010)
Was muss ich beachten beim Design der Klasse Point, damit ich sie als Schlüssel
in einer map benutzen kann? Dachte ich könnte das Problem mit
entsprechenden < Operator Überladungen umgehen, aber klappt nicht:bool operator < (const Point& p1, const Point& p2){...} bool Point::operator< (Point& p) {...}Stellt nicht die zweite Zeile einen Operator dar, der als linksseitigen
Operanden vc::Point akzeptiert? Oder verwechsel ich da etwas?Danke schonmal für etwas Tipps. Konnte dazu bisher noch keine wirkliche Hilfe finden.
-
error C2678: Binärer Operator '<': Es konnte kein Operator gefunden werden, der einen linksseitigen Operanden vom Typ 'const vc::Point' akzeptiert (oder keine geeignete Konvertierung möglich). Du hast 2 Möglichkeiten! Für weitere Tipps + in den Channel schreiben

-
Du kannst das Problem einfach lösen, indem du dir den Constructor von std::map einmal komplett anschaust.
template < class Key, class T, class Compare = std::less<Key>, // der Punkt ist für dich interessant class Allocator = std::allocator< std::pair<const Key, T> > > class map;http://www.cplusplus.com/forum/general/4444/
Bei den Operatoren kann ich dir nicht helfen, sollte aber gehen.
-
Der erste Operator sollte funktionieren. Wenn du den zweiten benutzen willst, sollte er const sein. Was du in deinen Codeschnippseln nicht zeigst: was ist vc und wo sind die Operatoren definiert?
-
Nick hat im Bezug auf den Operator unrecht.
Edit: Wobei mir beim weiteren Nachdenken Zweifel kommen, ob der Compiler wirklich bei dem ersten Fund auf der Suche nach einem Operator schluss machen darf. Aber irgendwie ist das auch egal, weil es doch gar keinen Sinn macht, den Vergleichsoperator als nicht-const-Methode zu implementieren, vor allem wenn die freistehende Funktion das dann auf einmal doch kann.
-
AlexSpritze schrieb:
std::map<Point, Vec3f> data;error C2678: Binärer Operator '<': Es konnte kein Operator gefunden werden, der einen linksseitigen Operanden vom Typ 'const vc::Point' akzeptiert (oder keine geeignete Konvertierung möglich)
bool operator < (const Point& p1, const Point& p2){...}Das sieht schon mal nicht schlecht aus. Es müsste funktionieren, wenn Du dies als freie Funktion in demselben Namensraum wie Deine Klasse Point deklarierst. Das mit dem Namensraum ist wichtig. Stichwort ADL (argument-dependent-lookup).
AlexSpritze schrieb:
bool Point::operator< (Point& p) {...}Das soll wohl eine nicht-statische Elementfunktion sein. Hier fehlen die zwei
consts:bool Point::operator< (Point const& p) const {...}Natürlich darfst Du nur eine der beiden Varianten verwenden. Aus Symmetriegründen macht man das typischerweise mit einer freien Funktion.
-
Decimad schrieb:
Nick hat im Bezug auf den Operator unrecht.
Wie meinen?
Ich hab mir die Operatoren nicht angesehen, weil ich mich damit nicht beschäftigt habe. Aber ein richtig formulierter und sinnvoller "kleiner als"-Operator sollte funktionierten. Nichts anderes passiert bei den Integralen Typen.
-
Naja, ich hatte das so interpretiert, dass du meintest dass es mit diesen (also denen vom TE) funtionieren sollte. Sorry falls ich das missverstanden habe.
-
@krümel: Ist die Symmetrie da echt so toll, dass man da so viele friend-Deklarationen in Kauf nimmt? Hab den Quelltext anderer noch nicht nach diesem Aspekt durchwühlt.
-
Decimad schrieb:
Edit: Wobei mir beim weiteren Nachdenken Zweifel kommen, ob der Compiler wirklich bei dem ersten Fund auf der Suche nach einem Operator schluss machen darf.
Die Suche findet "von innen nach außen" bzgl Gültigkeitsbereiche statt. Wird in einem Gültigkeitsbereich der Name gefunden, wird gestoppt. Ist der Compiler im globalen Gültigkeitsbereich gelandet, werden auch schließlich alle über using-Direktiven "eingebundenen" Namensräume durchsucht. Schließlich werden noch assoziierte Namensräume durchsucht (ADL). Es gibt aber auch eine Ausnahme, wo ADL nicht greift. Dass bei einem Fund die übergeordneten Gültigkeitsbereiche nicht mehr abgesucht werden führt zu dem "Hiding"-Effekt.
Lesetipps:
http://www.gotw.ca/publications/mill02.htm
http://www.gotw.ca/publications/mill08.htm
-
Decimad schrieb:
@krümel: Ist die Symmetrie da echt so toll, dass man da so viele friend-Deklarationen in Kauf nimmt?
Eine freie Funktion muss natürlich keine friend-Funktion sein. Ich würde eher erwarten, dass die Schnittstelle der Klasse Point all die für einen Vergleich nötigen Informationen rausrückt.
-
Da hast du natürlich Recht. *ditsch*
Edit: Wobei mich das Gefühl beschleicht, dass man da irgendwann doch unter Umständen Implementierungsdetails nach außen durchschleifen muss, dafür.