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 auf Location 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 😃


Log in to reply