Template: Vergleicherklasse durch Funktion ersetzten



  • Hallo,

    wenn man Templates verwendet kann man ja auch immer eine Vergleicherklasse mitangeben lassen, die zwei Objekte miteinander vergleicht:
    z.B.

    struct cmp_str 
    {
       bool operator()(char const *a, char const *b) 
       {
          return std::strcmp(a, b) < 0;
       }
    };
    
    ...
    template <class Temp, class Comp>
    ...
    

    Gibt es denn auch die Möglichkeit statt einer Klasse eine Funktion (vielleicht sogar eine Memberfunktion, die auf Membervariablen auch noch zugreift) zu übergeben? Die Version "template <class Temp, class Comp>" liefert einen Compilerfehler wenn man eine Funktion übergibt und "template <class Temp, function Comp>" funktioniert auch nicht.

    Gibt es noch ne andere Möglichkeit?

    Viele Grüße

    Andreas



  • Normalerweise ist es dann der Funktionstyp (bzw. Funktionszeigertyp), der als Templateparameter angegeben wird. Die Funktion selber wird per Argument (z.B. im Konstruktor) übergeben.

    Bei std::set kann das zum Beispiel so aussehen:

    #include <set>
    #include <string>
    
    bool CompareStrings(const std::string& Left, const std::string& Right)
    {
    	return Left < Right;
    }
    
    int main()
    {
    	// Mit Typedef:
    	typedef bool (*Function)(const std::string&, const std::string&);
    	std::set<std::string, Function> Set(&CompareStrings);
    
    	// Oder direkt:
    	std::set<std::string, bool (*)(const std::string&, const std::string&)> Set2(&CompareStrings);
    }
    

    Ist also je nach Fall recht hässlich, aber trotzdem möglich.



  • Und für Memberfunktionen kannst du mem_fun (http://www.cplusplus.com/reference/std/functional/mem_fun/) bzw. mem_fun_ref verwenden.



  • Hallo, erstmal vielen Dank für die Antworten!!!

    Hab leider mit Funktionsobjekten und co. noch nicht gearbeitet, versuche mich deshalb gerade in mem_fun einzuarbeiten.

    Hätte aber einmal ne Frage dazu:

    Ich kann ja auch schreiben:

    std::set<int, std::less<int> >
    

    Ist std::less nicht sogar der Standard, wenn man nichts angibt?

    Zumindest frage ich mich wie die Implementierung nun mit diesem Operator ein Objekt wiederfinden will. Ich meine mit std::less kann man zwar ein Array sortieren, aber wie finde ich heraus ob das Objekt wirklich vorhanden ist? Wenn less false liefert, dann kann es ja auch immer noch größer sein - wie macht das z.B. std::set dann um die Methode find anzubieten?

    Auf jeden Fall schonmal vielen Dank,

    viele Grüße

    Andreas



  • Wenn man einen <-Operator zur Verfügung hat (durch less) kann man alle anderen Vergleichsoperatoren nachbilden:

    a >= b <==> !(a < b)
    a == b <==> a >= b && b >= a
    a > b <==> a >= b && !(a == b)
    a <= b <==> !(a > b)

    (Vom Prinzip her, kann man bestimmt noch vereinfachen.)



  • Hi, stimmt hast recht - wenn mans so sieht kann man auch mit < alles ausdrücken, thx!!

    Ich hab mir das Tuturium auf http://www.cpp-tutor.de/cpp/le18/functors.html durchgelesen und wollte jetzt für std::set meine eigene Vergleichs-Funktion schreiben:

    class Testen
    {
    public:
    
    	int Wert;
    
    	bool Vergleicher2(int arg1, int arg2)
    	{
    		return (arg1 < Wert && arg2 < Wert);
    	}
    
    	void ausprobieren()
    	{
    		Wert = 4;
    		std::set<int, std::mem_fun<bool, int>(&Vergleicher2)> hallo;
    	}	
    };
    

    Das macht jetzt zwar noch keinen Sinn sollte aber halt ein Test für eine Memberfunktion sein, die auch noch auf Membervariablen zugreift.

    Leider liefert das ganz viele Compilerfehler, die ich noch nicht kenne:

    l:\meine visual projekte\avl2\avl2\avl2.cpp(70) : error C2276: '&': Ungültige Operation auf Ausdruck einer gebundenen Memberfunktion
    l:\meine visual projekte\avl2\avl2\avl2.cpp(70) : error C2770: Ungültige explizite template-Argumente für "std::const_mem_fun1_t<_Result,_Ty,_Arg> std::mem_fun(_Result (__thiscall _Ty::* )(_Arg) const)".
    l:\programme\visual 2008\vc\include\functional(598): Siehe Deklaration von 'std::mem_fun'
    l:\meine visual projekte\avl2\avl2\avl2.cpp(70) : error C2770: Ungültige explizite template-Argumente für "std::const_mem_fun_t<_Result,_Ty> std::mem_fun(_Result (__thiscall _Ty::* )(void) const)".
    l:\programme\visual 2008\vc\include\functional(589): Siehe Deklaration von 'std::mem_fun'
    l:\meine visual projekte\avl2\avl2\avl2.cpp(70) : error C2770: Ungültige explizite template-Argumente für "std::mem_fun1_t<_Result,_Ty,_Arg> std::mem_fun(_Result (__thiscall _Ty::* )(_Arg))".
    l:\programme\visual 2008\vc\include\functional(581): Siehe Deklaration von 'std::mem_fun'
    l:\meine visual projekte\avl2\avl2\avl2.cpp(70) : error C2770: Ungültige explizite template-Argumente für "std::mem_fun_t<_Result,_Ty> std::mem_fun(_Result (__thiscall _Ty::* )(void))".
    l:\programme\visual 2008\vc\include\functional(573): Siehe Deklaration von 'std::mem_fun'
    l:\meine visual projekte\avl2\avl2\avl2.cpp(70) : error C2133: 'hallo': Unbekannte Größe
    l:\meine visual projekte\avl2\avl2\avl2.cpp(70) : error C2512: 'std::set': Kein geeigneter Standardkonstruktor verfügbar

    Wenn ich <bool, int> hinter mem_fun weglasse klappt es leider auch nicht.

    Was muss ich ändern, damit es klappt?

    Viele Grüße

    Andreas



  • arrrr.
    war unsinn.
    sorry.



  • Hattest du gedacht du hättest den Fehler gefunden und hast das dann hinterher nochmal umeditiert oder wie darf ich das verstehen?^^



  • ich hab den fehler gefunden, bin dann aber draufgekommen dass mein vorschlag zur korrektur auch falsch war, und hatte keine zeit mehr das zu korrigieren und ausruprobieren.

    der fehler ist ziemlich offensichtlich: std::mem_fun ist kein typ, sondern eine helper-funktion (genauer: eine gruppe von gleichnamigen funktions-templates) zum erstellen von instanzen verschiedener typen.

    so in der art müsste es gehen, aber hab ich jetzt auch ausprobiert:

    std::set<int, std::mem_fun2_t<Testen, bool, int, int> > hallo(std::mem_fun<bool, int, int>(&Testen::Vergleicher2, this));
    

Log in to reply