Funktor statt Funktionszeiger



  • Ich habe eine Frage, die so erstmal nichts mit Standard-C++ zu tun hat:

    Ich möchte ein Programm in FLTK schreiben. Dabei kann ich den einzelnen Objekten Callback-Funktionen zuweisen, indem ich mir erst die Callback-Funktion definiere, z.B.:

    void xyz_callback(Fl_Widget *w, void *data)
    {
    ...
    }
    

    und dann diese Funktion bei dem jeweiligen Objekt registriere, mit

    int xyz_data;
    button->callback(xyz_callback, data);
    

    Jetzt stelle ich mir die Frage, was man machen muss, wenn man nicht eine einfache Funktion, sondern einen Funktor (Funktionsobjekt) als Callback-Funktion verwenden möchte.

    Könnte man die FLTK-Klasse (in diesem Fall z.B.) Button so kapseln, dass man im Endeffekt dem FLTK-Objekt eine Funktion als Callback-Funktion übergibt, die ihrerseits dann den Funktor aufruft?

    Ich komme irgendwie nicht weiter.

    Als Template-Parameter kann man den Funktor ja auch nicht einfach übergeben, also so etwas wie:

    class Funktor
    {
    public:
        void operator()(Fl_Widget *w, void *data);
    };
    
    template<Funktor F>
    void callback_funktion(Fl_Widget *w, void *data)
    {
        F(w,data);
    }
    

    Bei Templates müssen die Parameter ja statisch sein, d.h. ein Aufruf wie

    Funktor meinFunktor;
    button->callback(&(callback_funktion<meinFunktor>), data);
    

    würde nicht funktionieren...

    Hat irgendwer eine Idee?

    Felix :xmas2:

    P.S.: Ich hoffe, der Thread passt trotzdem her hin, die Lösung zu dem Problem sollte ja reines Standard-C++ sein. Ich möchte ja eigentlich nur einen Funktor an einer Stelle benutzen können, an der normalerweise ein Funktionszeiger erwartet wird.



  • Wieso nicht?

    #include <stdio.h>
    #include <conio.h>
    
    typedef void (*FunctionPtr)(void* userData);
    
    void SomeStupidFunction(FunctionPtr fp, void* userData)
    {
    	fp(userData);
    }
    
    class MyFunctor
    {
    public:
    	void operator () ()
    	{
    		printf("Winke-winke!\n");
    	}
    };
    
    template<class T> void WrapFunctor(void* functor)
    {
    	(*static_cast<T*>(functor))();
    }
    
    int main(int argc, char** argv)
    {
    	MyFunctor f;
    	SomeStupidFunction(WrapFunctor<MyFunctor>, &f);
    	_getch();
    
    	return 0;
    }
    

    p.S.: parameter kannst du dann z.B. mit boost::bind dranbinden (an den Funktor) - das selbst zu implementieren wäre mir entschieden zuviel Aufwand. Musst du dann halt in ein boost::function<void()> reinstecken, und das boost::function<void()> ist dann der Funktor den du an "WrapFunctor" übergibst.

    p.p.S.: oder du schreibst einfach bloss Funktoren die keine Parameter brauchen, frei nach dem "accumulate and fire" Pattern, bloss halt nicht über globale Variablen, sondern über Member -- dann ist das auch nicht so unsauber. boost::bind macht auch nix anderes, bloss halt automatisiert, dafür muss der Funktor rumkopiert werden (was aber egal sein sollte -- ein Funktor mit viel State ist eh böse).



  • Cool...

    Hast du das Beispiel selbst geschrieben oder wo hast du das her?


Anmelden zum Antworten