Hi, Ich habe eine Schnittstelle, die ein Funktionspointer erwartet. Gibt es eine Möglichkeit, statt eines Funktionszeigers an diese Funktion einen Funktor zu übergeben (ohne diese Schnittstelle zu ändern)?
was ist denn der Unterschied zwischen Funktor und Funktionspointer?
Evtl. mittels Template-Adapter-Funktion, die den Funktor ausführt, und als Funktionspointer weitergereicht werden kann...
Nein, anstelle eines Funktionspointers dürfte sich kein Functor übergeben lassen, da dieser aus mehr als nur einer Adresse besteht. Da aber ein Funktionspointer zur Laufzeit nichts anderes ist als eine Adresse, geht jeder Objektbezug verloren und muss "von Hand" an anderer Stelle mitgeführt werden. Aus diesem Grund weisen viele C-APIs an den Stellen, an denen sie Funktionspointer erwarten, die Möglichkeit auf, einen opaken Pointer auf irgendwas mitzugeben, der der aufgerufenen Funktion wiederum mitgegeben wird. Dieser opake Pointer eignet sich dazu, um z.B. den /this/-Pointer eines Objektes zu transportieren, ist aber natürlich von allen Typüberprüfungen ausgenommen, was die ganze Angelegenheit etwas, nun, fehlerträchtig machen kann. Bei ausreichender Disziplin seitens des Programmierers aber spricht nichts gegen die Verwendung derartiger Konstrukte.
Εrnst B✶ schrieb: > Evtl. mittels Template-Adapter-Funktion, die den Funktor ausführt, und > als Funktionspointer weitergereicht werden kann... meinst du so:
1 | void template<class Func> wrapFunctor(int i) |
2 | {
|
3 | Func f; |
4 | f(i); |
5 | }
|
da fehlt mir aber dann das konkrete Objekt. oder wie meinst du was anderes? mein Problem ist, dass ich beim Aufruf der Funktion bestimmte Zusatzinformationen brauch, die ich vorher bei Konstruktion des Funktors übergebe. das ganze wird benötigt, weil ich ein Stück Code wrappen möchte. In der wrappenden Umgebung sind aber zusatzinformationen bei Ausführung notwendig, die in der Originalumgebung nicht gebraucht werden, weswegen es dort eine zustandslose Funktion auch getan hat.
Rufus Τ. Firefly schrieb: > [...] Danke für deine Erläuterungen Je mehr ich darüber nachdenke, desto mehr bin ich auch der Meinung, dass es nicht funktioniert. Der einzige Weg, der mir einfällt wie man sowas von Sprachseite umsetzen könnte, würde nur auf einer von-Neumann-Architektur funktionieren
Wenn der von Rufus skizzierte Weg nicht geht, geht immer noch der klassische Weg, auch wenn er nicht schön ist. Der Schnittstelle gibst du einen Pointer auf eine freistehende Funktion. Dein 'arbeitendes Objekt' wird als globales (oder global statisch) ausgeführt (oder gleich als Pointer, wies dir eben besser passt) und die freistehende Funktion gibt dann an das Objekt weiter. So kann man die Kurve kratzen, um aus einer Funktionsumgebung wieder in eine Objektumgebung zu kommen.
1 | static MyClass* worker; |
2 | |
3 | static void callBackFnct() |
4 | {
|
5 | (*worker)(); |
6 | }
|
7 | |
8 | ...
|
9 | |
10 | worker = new MyClass( was auch immer das Objekt zur Arbeit braucht ); |
11 | API_fnct( callbackFnct ); |
12 | delete worker; |
Aber über eine Schnittstelle, die einen Funktionspointer haben will, kriegst du nun mal kein Objekt drüber. Da beisst die Maus keinen Faden ab.
Vlad Tepesch schrieb: > Der einzige Weg, der mir einfällt wie man sowas von Sprachseite umsetzen > könnte, würde nur auf einer von-Neumann-Architektur funktionieren Du wolltest die Funktion umkopieren, und jeweils eine eigene Kopie pro Funktor verwenden? Könnte gehen, aber inzwischen versuchen auch die Von-Neumann-Architekturen ihr Erbe loszuwerden... DEP, NX, und wie die ganzen Zusatz-Sicherheitsfeatures aktueller CPUs heissen... Vlad Tepesch schrieb: > meinst du so: > void template<class Func> wrapFunctor(int i) > { > Func f; > f(i); > } Genauso hatte ich das gedacht... in einem "qsort"-Beispiel-Fall ginge das auch... Ansonsten, wenn du keine Threads hast, könntest du mit einem globalen Funktor-Pointer arbeiten, den die Callback-Funktion benutzt. Mit Threads ginge das auch, müsstest dich dann aber selber um TLS-Variablen kümmern (pthread_setspecific, TlsAlloc, ...) Trotzdem bleiben einige Nebenbedinungen, wie z.B. kein verschachtelter Aufruf der Callback-Funktion, Aufruf immer aus demselben Thread der den Pointer an die API übergeben hat usw.
um auf die ursprüngliche Frage zurückzukommen: ich denke, nein.
Vlad Tepesch schrieb: > da fehlt mir aber dann das konkrete Objekt. Das Problem wirst du immer haben, wenn du nur einen Funktionszeiger übergibst. Vlad Tepesch schrieb: > mein Problem ist, dass ich beim Aufruf der Funktion bestimmte > Zusatzinformationen brauch, die ich vorher bei Konstruktion des Funktors > übergebe. Ah, das ist also das, was du eigentlich willst. Da wird dein Lösungsansatz dich aber nicht weiterbringen. In deinen Funktionszeiger kannst du nunmal keine Zusatzinformationen mit reinstecken, und Funktionsobjekte (was du "Funktor" nennst) funktionieren ganz anders und können nicht per Funktionszeiger übergeben werden. > das ganze wird benötigt, weil ich ein Stück Code wrappen möchte. > In der wrappenden Umgebung sind aber zusatzinformationen bei Ausführung > notwendig, die in der Originalumgebung nicht gebraucht werden, weswegen > es dort eine zustandslose Funktion auch getan hat. Da wurd dann wohl zu kurz gedacht. Eigentlich schreibt man solche Callback-Sachen doch immer so, daß ein zusätzlicher Zeiger auf void übergeben wird, mit dem der Benutzer des APIs machen kann, was er will. Ich denke, da wird man sich igendeinen unschönen Work-Around basteln müssen, aber wie der aussieht, hängt davon ab, in welchem Kontext das benutzt wird.
Rolf Magnus schrieb: > Eigentlich schreibt man solche > Callback-Sachen doch immer so, daß ein zusätzlicher Zeiger auf void > übergeben wird, mit dem der Benutzer des APIs machen kann, was er will. > Ich denke, da wird man sich igendeinen unschönen Work-Around basteln > müssen, aber wie der aussieht, hängt davon ab, in welchem Kontext das > benutzt wird. Ich hab eine Lösung für mein Problem gefunden. tatsächlich sieht der Funktionspointer so (ähnlich) aus: typdef void (*SendFunc)(Data*); der gerufene Code versendet für den aufrufenden Code das Datum. in der Wrapperumgebung ist das send aber etwas komplexer, so dass hier Infos zum aufgerufenen Wrapper benötigt werden. da ich in der glüchlichen Situation bin, dass ich den aufrufenden Code vorher den Puffer, den er beschreiben soll, mitteile kann ich Variante A: eine Zuordnung Puffer-Pointer->Wrapper (zB über std::map) machen. In der statischen CallBack kriegt man so das Objekt. oder Variante B: eine Struktur von Data ableiten, mit Zusatzinformationen (wrapper-this) versehen und dem aufrufenden Code geben. die Statische CallBack kommt dann per downcast an die Zusatzdaten (den Wrapper-Pointer)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.