Funktionspointer und std::tr1::function



  • Hallo,
    Ich habe zwei Fragen zu Funktionspointern:

    Funktionspointer auf Memberfunktionen sind grundsätzlich möglich, jedoch ist der Aufruf einer solchen Funktion anders. Ist es möglich, in einer queue von Funktionspointern (std::queue<void (*)(std::ifstream)>) sowohl Pointer auf normale Funktionen als auch Pointer auf Memberfunktionen zu speichern und aufzurufen?

    es gibt im TR1 das Template function. Ist dies einfach "modernerer" Funktionspointer (d.h. kann diese ersetzen) oder etwas völlig anderes? Ist dieses template möglicherweise in Bezug auf meine erste Frage hilfreich?

    Danke schon im Voraus!

    mfg
    mr x



  • Zu 1:
    So einfach geht das nicht. Ich weiß jetzt nicht ob es überhaupt geht, habe mich damit noch nicht beschäftigt. Wichtig ist für den Aufruf nicht-statischer Memberfunktionen, das du den this Zeiger benötigst. Ohne den geht nichts. Statische Memberfunktionen könntest du wahrscheinlich irgendwie umbiegen.



  • So einfach geht das nicht.

    Das habe ich mir schon gedacht... 😉

    Statische Memberfunktionen könntest du wahrscheinlich irgendwie umbiegen.

    Die dürften kein Problem sein, da sie ja nicht auf ein bestimmtes Objekt der Klasse bezogen sind. Leider ist die Funktion bei mir nicht statisch.



  • Wie gesagt, bei nicht-statischen Memberfunktionen benötigst du den this-Zeiger, ansonsten weiß man ja nicht für welches Objekt die Funktion ausgeführt werden soll.



  • Aber durch den this-Zeiger können sie allerdings nicht mehr mit normalen Funktionspointern gemischt werden (Aufruf der Funktion, auf den der Pointer zeigt und Deklaration muss gleich sein).

    Meine Frage zielte mehr darauf ab, ob es vielleicht Zeiger auf Memberfunktionen bezogen auf ein festgelegtes Objekt gibt.



  • Hier ist ein kleines Beispiel, wie du Member- und freie Funktionen mit std::function unter einen Hut bringst:

    #include <iostream>
    #include <tr1/functional>
    
    typedef std::tr1::function<void(int)> my_func_type; // dein funktionstyp
    
    struct test
    {
        void member_func(int v) { std::cout << "member_func: " << v <<  std::endl; }
    };
    
    void free_func(int v) { std::cout << "free_func: " << v << std::endl; }
    
    int main()
    {
        // zeiger auf member function
        test t;
        my_func_type func1 = std::tr1::bind(&test::member_func, t, std::tr1::placeholders::_1);
    
        // zeiger auf freie funktion
        my_func_type func2 = std::tr1::bind(&free_func, std::tr1::placeholders::_1);
    
        // aufruf funktioniert für beide gleich
        func1(23);
        func2(42);
    }
    


  • Danke!

    Das funktioniert und hat zugleich meine Frage nach std::tr1::function geklärt 👍



  • Noch eine kleine Frage:

    Was bedeutet "std::tr1::placeholders::_1"?



  • Das _1 repräsentiert das erste Argument. bind() erzeugt einen Funktor, bei dem die Platzhalter _1 , _2 etc. die eigentlichen Parameter darstellen. Beim "Aufruf" des function -Objekts werden die Argumente (im Beispiel 23 und 42) an die von function gespeicherte Funktion weitergeleitet.

    Ausführlichere Erklärungen findest du bei Boost.Bind.



  • Noch ergänzend zu tr1::function :
    Der eigentliche Vorteil von function gegenüber einem gewöhnlichen Pointer auf eine Funktion ist, dass die Funktion nicht genau diesen Parameter und genau diesen Rückgabewert haben muss, sondern dass die besagten Werte lediglich in die Ausgangswerte konvertierbar sein müssen. Außerdem akzeptiert er dank Templates auch Funktoren als Parameter.
    Beispiel:

    // Erste Funktion
    int f(int c) {
    	return c * c;
    }
    
    // Zweite Funktion
    double d(float f) {
    	return f * f;
    }
    
    // Funktor
    struct c {
    	int operator ()(int d) {
    		return d + d;
    	}
    };
    
    // Ruft Fkt.-Ptr. auf
    void aufruf(int (*fptr)(int)) {
    	fptr(34);
    }
    
    // Ruft Template auf
    template <typename T>
    void aufruf2(T t) {
    	t(54);
    }
    
    // Ruft tr1::function auf
    void aufruf3(std::tr1::function<int (int)> fkt) {
    	fkt(43);
    }
    
    aufruf(f); // Prima!
    aufruf(c()); // oh-oh! c kann nicht in int (*)(int) konvertiert werden
    aufruf(d); // oh-oh! double (*)(float) kann nicht in int (*)(int) konvertiert werden
    
    // Optionaler Tpl-Parameter zur Veranschaulichung
    aufruf2<int (int)>(f); // Prima!
    aufruf2<c>(c()); // Prima!
    aufruf2<double (float)>(d); // Prima!
    
    // Prima! Mit Konvertierungen
    aufruf3(f);
    aufruf3(c());
    aufruf3(d);
    

Anmelden zum Antworten