C-Callback an Objektmethode binden



  • Hallo Leute,

    ich habe ein Problem mit einem Callback, das ich irgendwie nicht gelöst bekomme.

    Hier kurz ein Beispiel:

    class MyClass
    {
    public:
    	MyClass()
    	{
    		callback_api(cb_func);   // genaue Deklaration: void callback_api (void (*cb) (int arg1, int arg2))   --> geht nicht, da 'cb_func()' eine Objektmethode ist
    	}
    
    	void cb_func(int arg1, int arg2)
    	{
    		mVar = arg1 + arg2;
    	}
    
    private:
    	int mVar;
    };
    

    Ich rufe im Konstruktor eines Objekts eine C-Funktion (API) auf, um eine Callback-Funktion festzulegen. Der Callback wird dann irgendwann von der verwendeten Bibliothek aufgerufen. Nun stehe ich aber vor dem Problem, dass ich den Callback nicht an eine Objektmethode binden kann. Dies ist jedoch wichtig, da ich auf Membervariablen zugreifen muss. Aber wie kann ich das lösen?

    Wenn ich die Methode statisch mache (s. Beispiel unterhalb), dann funktioniert der Aufruf 'callback_api(cb_func);', allerdings kann ich jetzt nicht mehr auf die Membervariablen/-methoden aus der Funktion heraus zugreifen.

    class MyClass
    {
    public:
    	MyClass()
    	{
    		callback_api(cb_func);   // würde hier funktionieren
    	}
    
    	static void cb_func(int arg1, int arg2)    // --> ist jetzt 'static void' statt 'void'
    	{
    		mVar = arg1 + arg2;      // zugriff auf 'mVar' nicht möglich, da statische Funktion
    	}
    
    private:
    	int mVar;
    };
    

    die nächste Überlegung war boost::bind:

    #include <boost/bind.hpp>
    
    class MyClass
    {
    public:
    	MyClass()
    	{
    		callback_api(boost::bind(&MyClass::cb_func, this, _1, _2));   // erzeugt Fehlermeldung
    	}
    
    	void cb_func(int arg1, int arg2)    
    	{
    		mVar = arg1 + arg2;
    	}
    
    private:
    	int mVar;
    };
    

    erzeugt aber so einen Fehler:

    error C2664: "void callback_api(void (__cdecl *)(int,int))" : Konvertierung von Argument 1 von "boost::_bi::bind_t<void,boost::_mfi::mf3<void,MyClass,int,int>,boost::_bi::list4<boost::_bi::value<T>,boost::arg<1>,boost::arg<2>>>" in "void (__cdecl *)(int,int)" nicht möglich

    Ich habe zwar noch irgendwelche Ansätze mit std::bind und lambda-Funktionen gesehen, aber nichts hat so recht geholfen. Habt ihr eine Idee?

    viele Grüße,
    SBond



  • class MyClass
    {
    public:
    	MyClass()
    	{
    		gptr = this;
    		callback_api(cb_func);
    	}
    	static void cb_func(int arg1, int arg2)
    	{
    		gptr->mVar = arg1 + arg2;
    	}
    private:
    	static MyClass * gptr;
    	int mVar;
    };
    

    ?

    gptr muß halt stets korrekt und gültig sein.



  • Es ist üblich, dass C Callbacks einen void* Parameter haben, durch den man Benutzerdaten weiterreichen kann.

    Du scheinst da ein recht exotisches API zu verwenden.



  • Caligulaminus schrieb:

    class MyClass
    {
    public:
    	MyClass()
    	{
    		gptr = this;
    		callback_api(cb_func);
    	}
    	static void cb_func(int arg1, int arg2)
    	{
    		gptr->mVar = arg1 + arg2;
    	}
    private:
    	static MyClass * gptr;
    	int mVar;
    };
    

    ?

    gptr muß halt stets korrekt und gültig sein.

    ne das geht leider nicht. 😞

    gptr = this;   // --> error LNK2001: Nicht aufgelöstes externes Symbol ""private: static class MyClass* MyClass::gptr (?gptr@MyClass@@0PAV1@A)".
    

    Bin mir auch nicht sicher ob das so eine gute Idee wäre. Das würde doch auch bedeuten, dass ich nur eine Instanz dieser Klasse verwenden dürfte, oder? Ich habe zuvor nie mit callbacks gearbeitet. Sind statische Funktion wirklich das Mittel der Wahl? 😕

    @manni66: Einige OpenSSL-Callback-Funktionen bieten 'void* arg'-Paramerter an, über das ich einen this-Pointer übergeben könnte. Die Callback-Funktion die ich nutze bietet es allerdings nicht an :(.

    Geht sowas nicht mit std::bind oder lambda zu lösen?

    LG,
    SBond



  • Für statische Member benötigst du noch eine separate Definition (in der Source-Datei):

    MyClass* MyClass::gptr;
    

    (sollte man eigentlich wissen)



  • SBond schrieb:

    Geht sowas nicht mit std::bind oder lambda zu lösen?

    Nein



  • ja sorry. Habe jetzt knapp ein Jahr nicht mit mit C++ gearbeitet.

    Danke für die Hilfe 🙂


Anmelden zum Antworten