Kleiner Operator: Richtig überladen?
-
Hallo,
wir arbeiten im Moment mit Maps. Dort gibt es ja dann den STL Sortieralgorithmus std::less.
Nun stehe ich vor einem Problem:
Wir benutzen
std::map<Location, Node> nodes;
Wobei Location je einen Wert für die xAchse und yAchse enthält.
Einige benutzen dafür den std::pain Container, andere allerdings haben sich dafür eine eigene Klasse Location geschrieben, die als Attribute die beiden Achsen enthalten.Um die Map nun richtig anwenden zu können muss ich den <Operator ja überladen.
bool Location::operator<(const Location& loc) const { return (this->xAxis < loc.xAxis && this->yAxis < loc.yAxis); }
Ergibt meiner Meinung nach nicht wirklich viel Sinn. Wie kann ich in so einem Fall den kleiner Operator korrekt überladen?
-
Warum ergibt das keinen Sinn?
Dann mach es doch einfach so, wie es Sinn ergibt im Zusammenhängenden Kontext..
-
Nunja, woran erkennt man denn, ob eine Location kleiner ist als die andere?
-
skizZ schrieb:
std::pain
skizZ schrieb:
Um die Map nun richtig anwenden zu können muss ich den <Operator ja überladen.
Musst du nicht unbedingt, du kannst auch einen Funktor oder eine Funktion schreiben, die den Vergleich übernimmt. Wäre meiner Ansicht nach auch besser, wenn der
operator<
keine wirklich sinnvolle Aufgabe (Vergleich zweier Vektoren/Koordinaten) übernimmt.Funktion (ordnet zuerst nach x und dann nach y):
bool CompareLocations(const Location& Left, const Location& Right) { if (Left.xAxis != Right.xAxis) return Left.xAxis < Right.xAxis; else return Left.yAxis < Right.yAxis; }
Deklaration:
typedef bool (*FunctionType) (const Location&, const Location&); // Funktionszeiger als Typ std::map<Location, Node, FunctionType> Map(CompareLocations); // oder std::map<Location, Node, FunctionType> Map(&CompareLocations);
Funktor:
struct CompareLocationFunctor { bool operator() (const Location& Left, const Location& Right) { // ... } };
Deklaration:
std::map<Location, Node, CompareLocationFunctor> Map;
Edit: Fehler korrigiert.
-
skizZ schrieb:
Nunja, woran erkennt man denn, ob eine Location kleiner ist als die andere?
Macht wie gesagt keinen Sinn, den
operator<
dafür zu überladen. Operatoren sollten nur überladen werden, wenn sich der Sinn direkt erschliesst. Wie will man sagen, ob ein Vektor grösser ist als ein anderer?Deshalb würde ich den Weg über die Funktion oder das Funktionsobjekt (=Funktor) gehen.
-
Hi,
std::pain... OOPS
So, bitte nimm es mir nicht übel Nexus. Aber wie genau wende ich das an?
Ich habe folgende Klasse
class Graph { public: std::map<Location, Node> nodes; Graph(); ~Graph(void); void readMap(std::string fileName); static void test(); //Routenberechnung List<Location>& bfSearchForShortestPath(const Location& s, const Location& d, List<Location>& route); };
Füge ich nun die Funktion ein und haue den Funktionsnamen noch hinter Node, funktioniert das so aber nicht
-
skizZ schrieb:
So, bitte nimm es mir nicht übel Nexus. Aber wie genau wende ich das an?
Wieso sollte ich es dir übel nehmen?
Du musst das Vergleichsprädikat (Funktion oder Funktor) als drittes Templateargument bei
std::map
mitgeben. Also so, wie ich es oben geschrieben habe (unter "Deklaration").
-
Hi,
wenn ich das so mache:
#pragma once #include <map> #include <string> #include "Node.h" #include "List.h" bool CompareLocations(const Location& Left, const Location& Right) { if (Left.xAxis != Right.xAxis) return Left.xAxis < Right.xAxis; else return Left.yAxis < Right.yAxis; } class Graph { public: std::map<Location, Node, CompareLocations> nodes; Graph(); ~Graph(void); void readMap(std::string fileName); static void test(); //Routenberechnung List<Location>& bfSearchForShortestPath(const Location& s, const Location& d, List<Location>& route); };
Bekomm ich
c:\dokumente und einstellungen\florian\eigene dateien\visual studio 2005\projects\futurecar_1\graph.h(18) : error C2923: "std::map": "CompareLocations" ist kein gültiges template-Typargument für den _Pr-Parameter. c:\dokumente und einstellungen\florian\eigene dateien\visual studio 2005\projects\futurecar_1\graph.h(7): Siehe Deklaration von 'CompareLocations' c:\dokumente und einstellungen\florian\eigene dateien\visual studio 2005\projects\futurecar_1\graph.cpp(16) : error C2084: Funktion 'bool CompareLocations(const Location &,const Location &)' hat bereits einen Funktionsrumpf c:\dokumente und einstellungen\florian\eigene dateien\visual studio 2005\projects\futurecar_1\graph.h(7): Siehe vorherige Definition von 'CompareLocations'
-
Sorry, ich habe vorhin was Falsches erzählt, ich habe es mit den Sortierfunktionen verwechselt.
Als drittes Template-Argument muss der Funktionstyp angegeben werden. Das ist ein Zeiger auf eine Funktion, die einen
bool
zurückgibt und zwei Const-Referenzen aufLocation
als Parameter hat:typedef bool (*FunctionType) (const Location&, const Location&);
Die Deklaration sieht dann so aus:
std::map<Location, Node, FunctionType> Map(CompareLocations);
Wie du siehst, wird die eigentliche Funktion als Konstruktorargument der
map
übergeben.Edit: Ich habe den Fehler in meinem oberen Post korrigiert.
-
Hi,
sorry, aber er zeigt mir hier
std::map<Location, Node, FunctionType> nodes(CompareLocations);
noch immer an: error C2061: Syntaxfehler: Bezeichner 'CompareLocations'
-
Versuch mal
std::map<Location, Node, FunctionType> nodes(&CompareLocations);
Die Funktion heisst ja schon so, oder?
-
Hi,
nee das funktioniert auch nicht
hier nochmal der schnipsel
bool CompareLocations(const Location& Left, const Location& Right) { if (Left.xAxis != Right.xAxis) return Left.xAxis < Right.xAxis; else return Left.yAxis < Right.yAxis; } class Graph { public: typedef bool (*FunctionType) (const Location&, const Location&); // Funktionszeiger als Typ std::map<Location, Node, FunctionType> nodes(CompareLocations);
-
Ah, du kannst den Konstruktor natürlich nicht bei der Deklaration aufrufen.
Schreib in die Klassendefinition:
typedef bool (*FunctionType) (const Location&, const Location&); std::map<Location, Node, FunctionType> nodes;
Und in den Konstruktor:
Graph::Graph() : nodes(CompareLocations) { }
-
skizZ schrieb:
Hi,
wenn ich das so mache:
#pragma once #include <map> #include <string> #include "Node.h" #include "List.h" bool CompareLocations(const Location& Left, const Location& Right) { if (Left.xAxis != Right.xAxis) return Left.xAxis < Right.xAxis; else return Left.yAxis < Right.yAxis; } class Graph { public: std::map<Location, Node, CompareLocations> nodes; Graph(); ~Graph(void); void readMap(std::string fileName); static void test(); //Routenberechnung List<Location>& bfSearchForShortestPath(const Location& s, const Location& d, List<Location>& route); };
CompareLocations muss ein Funktor sein, sonst geht es nicht als Templateargument:
struct CompareLocations { bool operator()(const Location& Left, const Location& Right) { if (Left.xAxis != Right.xAxis) return Left.xAxis < Right.xAxis; else return Left.yAxis < Right.yAxis; } }; class Graph { public: std::map<Location, Node, CompareLocations> nodes; //... };
-
Tachyon schrieb:
CompareLocations muss ein Funktor sein, sonst geht es nicht als Templateargument:
Nein, es geht auch mit einer Funktion. Nur muss man da eben den Funktionszeiger-Typen als Template-Argument angeben, so wie ich das gezeigt habe.
bool CompareLocations(const Location& Left, const Location& Right) { if (Left.xAxis != Right.xAxis) return Left.xAxis < Right.xAxis; else return Left.yAxis < Right.yAxis; } int main() { typedef bool (*Function) (const Location&, const Location&); std::map<Location, float, Function> Map(&CompareLocations); }
-
Danke,
nun funktioniert es