Funktionen zur Laufzeit erzeugen und registrieren
-
Hallo,
ich bin auf der Suche nach eine Möglichkeit, das erzeugen und registrieren von Callbackfunktionen zu automatisieren.
Im Augenblick funktioniert es so:
Ich habe eine virtuelle Basisklasse, wenn man die implementiert muss man zwei Funktionen definieren, die später in einen Wrapper kommen, der wiederum als Callbackfunktion registriert wird.Hier mal ein Beispiel:
class LogicHandler { virtual void doProcessing() = 0; virtual float processingFrequency() = 0; }; class SomeConcreteHandler : public LogicHander { virtual void doProcessing() { tu_was_in_der_klasse(x,y,z);} virutal float processFrequnecy() { if (bla) return 1; else return 2;} }; class SomeOtherConcreteHandler : public LogicHandler { //bla bla bla };
Im main meines Programms werden die Instanzen erzeugt. Zu jeder instanz gibt es eine wrapper-funktion, die dann als Callback registriert wird:
LogicHandler* handler1 = new SomeConcreteHandler(); LogicHandler* handler2 = new SomeOtherConcreteHandler(); float callbackWrapper1(void*, float, float, float) { handler1->doProcessing(); return handler1->processingFrequnecy(); } float callbackWrapper2(void*, float, float, float) { handler2->doProcessing(); return handler2->processingFrequnecy(); } RegisterCallbackInApi(callbackWrapper1); RegisterCallbackInApi(callbackWrapper2);
Und das hätte ich jetzt gerne dynamisiert.
Und zwar habe ich gedacht an einen vector von Pointern auf LogicHandler.
Der Vector muss dann abgeklappert werden und für jedes Element eine solche Wrapper-Funktion erzeugt und registriert werden.Wie kann man das machen?
-
bin mir sicher, ob ich dein problem verstanden habe.
mögliche lösung im pseudocode:LogicHandler* handler1 = new SomeConcreteHandler(); LogicHandler* handler2 = new SomeOtherConcreteHandler(); float callbackWrapper(LogicHandler* handler, void*, float, float, float) { handler->doProcessing(); return handler->processingFrequnecy(); } std::vector<LogicHandler*> v; v.push_back(handler1); v.push_back(handler2); for_each(i in v) callbackWrapper(*i, ...)
-
virtuelle Basisklasse
hae?
In C oder C++ koennen keine Funktionen dynamisch zur Laufzeit generiert werden. Auch der Umweg ueber Objekte ist ein Trugschluss, da keine neue Funktionaliaet (ohne weiteres) generiert werden kann.
Aber wahrscheinlich hast du dich unklar ausgedrueckt.
-
polymorphism ftw schrieb:
bin mir sicher, ob ich dein problem verstanden habe.
mögliche lösung im pseudocode:LogicHandler* handler1 = new SomeConcreteHandler(); LogicHandler* handler2 = new SomeOtherConcreteHandler(); float callbackWrapper(LogicHandler* handler, void*, float, float, float) { handler->doProcessing(); return handler->processingFrequnecy(); } std::vector<LogicHandler*> v; v.push_back(handler1); v.push_back(handler2); for_each(i in v) callbackWrapper(*i, ...)
Das Problem ist, dass die wrapper funktion genau die Signatur haben muss
typedef float (* callback_fun)(void * , float, float, float)
und ich da jetzt nicht einfach einen zusätzlichen Parameter LogicHandler* davorfummeln kann, denn dann stimmt die Signatur nicht mehr und ich kann das Callback nicht mehr registrieren.
-
Na der void-Zeiger wird wohl für genau sowas da sein.
-
Richtig, aber ich brauche ja nichtsdestotrotz n viele von diesen Funktionen. Oder kann ich eine Funktion n-mal mit unterschiedlichen Parametern registrieren? Ich glaube nicht.
-
PhilippM schrieb:
Oder kann ich eine Funktion n-mal mit unterschiedlichen Parametern registrieren?
Dazu müsste man erstmal wissen, womit du überhaupt arbeitest. Aber wenn es nicht geht, rufst du halt mehrere Handler in der Callback-Funktion auf.
-
Kannst du der "RegisterCallbackInApi" mehrere Callbacks angeben, die alle ausgeführt werden, oder bloss einen?
Und kannst du den "void*" der an die Callback-Funktion übergeben wird irgendwo angeben, oder kommt da irgendwas anderes daher, dessen Wert du nicht bestimmen kannst?
Und wie willst du den Returnwert des Callbacks bestimmen, wenn es mehrere Callbacks gibt?
-
hustbaer schrieb:
@PhilippM:
Und wie willst du den Returnwert des Callbacks bestimmen, wenn es mehrere Callbacks gibt?Naja, der returnwert bestimmt sich ja aus dem handler->processingFrequnecy(), und da handler in dem falle ja vom void* runtergecastet wäre, ginge das. Aber mir ist nich klar, wie ich n-mal die gleiche funktion mit unterschiedlichen Parametern registrieren können soll.
Also hier mal der entscheidende abschnitt aus der API-Doku:
XPLM_API void XPLMRegisterFlightLoopCallback(XPLMFlightLoop_f inFlightLoop,
float inInterval,
void * inRefcon);This routine registers your flight loop callback. Pass in a pointer to a flight loop function and a refcon. inInterval defines when you will be called. Pass in a positive number to specify seconds from registration time to the next callback. Pass in a negative number to indicate when you will be called (e.g. pass -1 to be called at the next cylcle). Pass 0 to not be called; your callback will be inactive.
typedef float (* XPLMFlightLoop_f)(float inElapsedSinceLastCall,
float inElapsedTimeSinceLastFlightLoop,
int inCounter,
void *inRefcon);This is your flight loop callback. Each time the flight loop is iterated through, you receive this call at the end. You receive a time since you were last called and a time since the last loop, as well as a loop counter.
Your return value controls when you will next be called. Return 0 to stop receiving callbacks. Pass a positive number to specify how many seconds until the next callback. (You will be called at or after this time, not before.) Pass a negative number to specify how many loops must go by until you are called. For example, -1.0 means call me the very next loop. Try to run your flight loop as infrequently as is practical, and suspend it (using return value 0) when you do not need it; lots of flight loop callbacks that do nothing lowers x-plane's frame rate.
Your callback will NOT be unregistered if you return 0; it will merely be inactive.
The reference constant you passed to your loop is passed back to you.
Wenn ich das richtig verstehe, müsste ich mit hilfe dieser magischen "reference constant" dass alles machen können.
-
Hey, das funktioniert tatsächlich... Ich hatte befürchtet, dass es beim Aushängen eines Callbacks Probleme gibt, also dass mir alles ausgehängt wird, wenn ich ein UnregisterCallback(function_ptr, void_ptr); mache, aber nein, es wird tatsächlich nur die zum void_ptr passende funktion ausgehängt. Fantastisch.
Ich hasse zwar dieses C-Style void*-Geraffel, aber wenigstens funktioniert's hier mal...