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?