Callback und Templateklasse
-
Hallo,
ich mal wieder. Folgendes Problem:
Ich habe eine Templateklasse und eine Funktion. Die Funktion soll eine Methode aus der Templateklasse aufrufen:
void handleCallback( int bla ) { //Problem: //Hier soll update() aus Bar aufgerufen werden. } template< typename Foo > class Bar { void loop( ) { //Wird bei bestimmten Events aufgerufen, kann ich nicht beeinflussen. callback = handleCallback; //'callback' ist ein Funktionszeiger: //extern void (*func)(int param); } //Soll aufgerufen werden, sobald etwas passiert ist. bool update( Anything &doesnt_work ) { //do something... return true; } }An der Signatur von
handleCallbackkann ich nix ändern. Wie kann ich aus dieser Funktion aber Bar bescheid sagen, das etwas passiert ist? Konkret will ich die update()-Methode aus Bar aufrufen.
Ist das überhaupt möglich? (mit meinen Kenntnissen nicht
)
Kann jemand helfen?MfG. Christoph Ludwig
-
Es gibt kein Bar. Es gibt nur verschiedene Bar<Foo>. Welches Foo darf es denn sein?
-
Ja eben, das ist es ja, was mich stört.
Kann man das irgendwie umgehen?
-
Wie soll deiner Meinung nach handleCallback ein Bla informieren, wenn der Funktion kein derartiges Objekt übergeben werden kann? handleCallback ist dahingehend schlecht designed. Denn für UserData gibt man meistens noch nen void-Pointer mit, den man sich je nach Situation zurechtcastet.
Die einzige Möglichkeit die ich sehe wäre entweder ein globales Bar-Objekt, oder ein Manager, der Bar-Objekte verwaltet und dem du dann je nach Bedarf Objekte entnehmen kannst.Da aber callback ein Member ist, möchtest du wohl dass callback auch "this" kennt/verwendet. Das wird nicht leicht sein...
Was soll eigentlich dieser "int bla"-Parameter genau an/darstellen?
-
Wie soll deiner Meinung nach handleCallback ein Bla informieren
Weis ich nicht. Deshalb frag ich doch.
Da aber callback ein Member ist,...
Falsch. Konkret:
callback ist nen Funktionszeiger aus dem Framework, welches ich verwende: http://www.allegro.cc/manual/api/mouse-routines/mouse_callbackUnd das kann ich nunmal nicht ändern.
Aber aus den 2 Antworten höre ich raus, das dies nicht möglich ist(, was ich mir ja schon gedacht hab). Hätte ja sein können, ihr kennt einen Trick dazu...
-
ChristophLu schrieb:
Ja eben, das ist es ja, was mich stört.
Kann man das irgendwie umgehen?Nein, denn es gibt schlicht und einfach kein Bar. Du musst uns daher die Frage beantworten, was du mit Bar ohne Templateparameter meinst, dann kann man eventuell eine Lösung finden.
Um Mal einen Vergleich zu bringen: Im Moment hast du eine Plätzchenform und willst die Methode essen() aufrufen, die es aber nur für fertige Plätzchen gibt. Also sag uns, was du mit dem essen() der Plätzchenform erreichen willst. Willst du dadurch vielleicht alle Plätzchen auf einmal essen?
-
Ist das denn so schwer zu verstehen, Sepp?
Anwendung:
#include "Bla.hpp" int main() { Bla<int> x; x.loop(); }Nehmen wir an, das Callback sagt Bescheid, wenn die Maus sich ändert. Dann soll update() eine Meldung ausgeben, das sich die Maus geändert hat. Das ist das Ziel.
Mit den gegebenen Möglichkeiten(dadurch, das Bla ein Template ist und die eigentliche Callback eher ungeeignet zu sein scheint) geht es demnach nicht(bzw. mir wäre nichts bekannt).Wenn ich so überlege: Kann man nicht eine Basis-Klasse mit den virtuellen Methoden loop() und update() erstellen und von der Basis-Klasse nen globalen Zeiger speichern. Dann könnte handleCallback doch darauf zugreifen oder? Nur müsste ich dann Bla als Singleton machen, da sich das bei mehreren Instanzen zwickt.
-
Ich stimme zu. Das einzige was mir dazu einfällt ist ein globales Objekt. Wie das konkret am optimalsten aussieht, kommt auf die Details an. Anders als global jedenfalls wirst du von der callback-Funktion nichts ansprechen können, das außerhalb von ihrem Scope liegt.
-
Gut, dann werd ich das so probieren. Mein Ansatz wäre etwas in der Art:
//Damit ich das Problem mit den Templates nicht mehr hab. struct BasicBla { virtual bool loop( ) = 0; virtual bool update( ) = 0; }; //Damit handleCallback auf Bla<...> zugreifen kann. BasicBla *globalBla = NULL; //Wird bei einem Event aufgerufen. void handleCallback( int blubb ) { if( globalBla != NULL ) { globalBla->update(); } } //Für den User template< typename Foo > class Bla : public BasicBla { Bla( ) { //Im einfachsten Fall kann ich doch hier prüfen, ob globalBla != NULL ist. So in etwa: if( globalBla != NULL ) { throw std::runtime_error( "Bla existiert schon!" ); } //Diese instanz global speichern, damit handleCallback darauf zugreifen kann. globalBla = this; } bool loop( ) { callback = handleCallback; } bool update( ) { //... } }; int main() { Bla<int> x; x.loop(); return 0; }Kann man das so machen oder gibts da bessere Wege?
-
Hmm, da stellt sich mir ein weiteres Problem auf.
Jetz hab ich das so Umgesetzt wie oben geschrieben, nur hab ich jetzt logischerweise das Problem, das sich mein Programm beendet, weil kein Event kommt.Schematisch sieht meine loop()-Funktion so aus:
function loop callback setzen endNach dem callback-setzen wird sie logischerweise beendet. Was mach ich jetzt? Wie "warte" ich auf die Events?
Das ganze hab ich ja gemacht, damit ich vom ressourcenfressenden Polling auf schonendere Interrupts wechsle. Also kann ich ja schlecht mit ner While-Schleife auf Nachrichten warten. Dann hab ich ja wieder Polling...
Sollte dann also etwa so aussehen:
function loop callbacks setzen irgendwie warten endJemand ne Idee?
-
Hat sich erledigt. Ab und zu sollte man die Doku lesen

rest() ...