memberfunktion als funktionsparameter



  • hallo,
    ich hab folgendes problem

    int foo2(int (*func)(int a))
    {/*...*/};
    
    class A
    {
      public:
        int foo(int a){/*...*/};
        int bla()
        {
          //...
          return foo2(&foo); // Fehler error C2276: '&': Ungültige Operation auf Ausdruck einer gebundenen Memberfunktion
        };
    };
    

    so wollte nun mal fragen, ob man das problem lösen kann und ich trotzdem den entsprechenden zeiger auf die funktion übergeben kann?
    danke schon mal im voraus.



  • foo ist eine nicht-statische Elementfunktion. Einen Zeiger bekommst Du mit &A::foo. Das ist dann aber auch ein Zeiger auf eine Elementfunktion und kein Zeiger auf eine freie Funktion, wie es foo2 erwartet. Der Unterschied besteht darin, dass die Elementfunktion ja noch den impliziten this-Parameter eines bestimmten Klassentyps bekommt.

    Gruß,
    SP



  • danke für die schnelle antwort, gibt es also keine mögichkeit die memberfunktion als parameter zu verwenden?


  • Administrator

    FAQ: http://www.c-plusplus.net/forum/viewtopic-var-t-is-39450.html

    Zusätzliche Hilfsmittel:
    - Boost.Bind (oder std::tr1::bind)
    - Boost.Function (oder std::tr1::function)

    Grüssli



  • ich habs jetzt hinbekommen, ist zwar nicht schön geht aber, glaub ich.
    hab alle notwendigen daten in static variablen zwischengspeichert und die memberfunktionen dann static gemacht, dann konnte ich die pointer natürlich benutzen. wie gesagt vom stil gefällt mir das nicht sonderlich gut.



  • Gut dass dir das nicht gefällt, ist ja auch Pfusch.
    Übergib entweder einen Member-Function-Pointer, oder über gib einen Funktor.



  • na das mit den member-function-pointer funktioniert ja gerade nicht, wegen dem impliziten this-pointer, oder hab ich da jetzt was verpasst?


  • Administrator

    FreakyBKA schrieb:

    na das mit den member-function-pointer funktioniert ja gerade nicht, wegen dem impliziten this-pointer, oder hab ich da jetzt was verpasst?

    1. Es hat niemand behauptet, dass es nicht geht. Es geht nur nicht so, wie du es gemacht hast.
    2. Ich habe einen FAQ Link gepostet, welcher dir zeigt, wie es gehen würde. Aber anscheinend empfindest du dies als unwichtig.
    3. Ich habe dir zwei zusätzliche Hilfsmittel genannt, wenn du nach diesen gesucht hättest, hättest du weiter Lösungsmöglichkeiten gefunden. Aber die interessieren dich wohl nicht?

    😕

    Grüssli



  • der FAQ-Link hilft mir nicht, wenn ich den inhalt richtig verstanden habe. da muss man ja explizit wissen von welchem objekttyp die funktion stammt, dort war es das X. das will ich aber halt nicht. und die boost-lib will ich nicht verwenden, das zu erklären wäre off-topic, also daher helfen mir die beiden anderen sachen nicht. das hätte ich vllt vorher schreiben sollen, sorry, aber ich hab mir das durchaus angeschaut 😉



  • Es gibt noch eine Alternative. In vielen C APIs übergibt man nicht nur einen Funktionszeiger sondern auch einen void* für den "Kontext". Dieser Zeiger könnte die Adresse eines Objektes halten:

    #include <iostream>
    
    typedef int (*handler_t)(const void* context, int);
    
    void mach_was(handler_t h, const void* context)
    {
    	int k = h(context,23);
    	std::cout << k << '\n';
    }
    
    class A
    {
    	int faktor;
    public:
    	explicit A(int f) : faktor(f) {};
    
    	int multiplizieren(int a) const
    	{
    		return a * this->faktor;
    	}
    };
    
    int verpackung_fuer_A(const void* context, int t)
    {
    	return static_cast<const A*>(context)->multiplizieren(t);
    }
    
    int main()
    {
    	A dings (42);
    	mach_was(&verpackung_fuer_A,&dings);
    }
    

    Das mit dem Casting ist natürlich mit Vorsicht zu genießen. Wenn Du Elementfunktionen aufrufen willst, die nicht const sind, musst Du das const vor void jeweils entfernen.

    Und sonst gibt's ja noch Templates. Das einfachste ist, Deine foo2 in ein Template zu verwandeln und per std::bind1st(std::mem_fun(...)) einen Funktor zu erzeugen.

    Gruß,
    SP



  • Falls der "Handler" nicht kopierbar sein muss, geht es auch so:

    #include <iostream>
    
    class handler
    {
    private:
    	handler& operator=(handler const&);
    protected:
    	~handler() {}
    public:
    	virtual int operator()(int a) const = 0;
    };
    
    void mach_was(const handler& h)
    {
    	int k = h(23);
    	std::cout << k << '\n';
    }
    
    //----------[ Magie beginnt hier ]----------
    
    template<class Class>
    class mf_wrapper_const : public handler
    {
    public:
    	mf_wrapper_const(Class const* po, int(Class::*pf)(int)const)
    		: pobj(po), pmf(pf) {}
    	int operator()(int a) const {return (pobj->*pmf)(a);}
    private:
    	Class const* pobj;
    	int (Class::*pmf)(int) const;
    };
    
    template<class Class>
    class mf_wrapper_nonconst : public handler
    {
    public:
    	mf_wrapper_nonconst(Class* po, int(Class::*pf)(int))
    		: pobj(po), pmf(pf) {}
    	int operator()(int a) const {return (pobj->*pmf)(a);}
    private:
    	Class * pobj;
    	int (Class::*pmf)(int);
    };
    
    template<class Clazz>
    inline mf_wrapper_const<Clazz>
    wrap(Clazz const* po, int(Clazz::*pmf)(int)const)
    { return mf_wrapper_const<Clazz>(po,pmf);}
    
    template<class Clazz>
    inline mf_wrapper_nonconst<Clazz>
    wrap(Clazz * po, int(Clazz::*pmf)(int))
    { return mf_wrapper_nonconst<Clazz>(po,pmf);}
    
    //----------[ Magie endet hier ]----------
    
    class A
    {
    	int faktor;
    public:
    	explicit A(int f) : faktor(f) {}
    	int multiplizieren(int a) const {return a*faktor;}
    };
    
    int main()
    {
    	A a (42);
    	mach_was(wrap(&a,&A::multiplizieren));
    }
    

    Gruß,
    SP



  • Sebastian Pizer schrieb:

    Es gibt noch eine Alternative. In vielen C APIs übergibt man nicht nur einen Funktionszeiger sondern auch einen void* für den "Kontext".

    Das ist "undefined behavior". Callbacks für C APIs müssen "extern C" definiert sein, und das geht nur mit freien Funktionen, jede Form einer Member Function scheidet damit aus.


  • Administrator

    FreakyBKA schrieb:

    der FAQ-Link hilft mir nicht, wenn ich den inhalt richtig verstanden habe. da muss man ja explizit wissen von welchem objekttyp die funktion stammt, dort war es das X. das will ich aber halt nicht.

    Eine Memberfunktion gehört nunmal einer Klasse und braucht halt ein Objekt um aufgerufen zu werden. Man kann dies allerdings in einem Funktor zusammenpacken und immer gemeinsam rumschieben.

    FreakyBKA schrieb:

    und die boost-lib will ich nicht verwenden, das zu erklären wäre off-topic, also daher helfen mir die beiden anderen sachen nicht.

    Das ist schade, dass du die nicht verwenden kannst, denn die würden dir entsprechende allgemeine Schnittstellen anbieten. Allerdings sind die eben auch in std::tr1 vorhanden, also dem Technical Report 1 von C++. Viele Kompiler unterstützen den TR1, vielleicht kannst du diesen Verwenden.

    Ansonsten bleiben dir nur ein paar Alternativen:
    - Selber bauen. Es gibt da zum Teil ganz einfache Vorgehensweisen, sofern du die Schnittstellenspezifikation ein wenig einschränken kannst.
    - Über den bereits erwähnten C++ Header <functional> kann man sich auch etwas selber zusammenbauen. Allerdings vor allem nur Funktoren, welche man als Templateparameter übergeben kann. Die Empfängerfunktion müsste dann ein Funktionstemplate sein und abspeichern geht damit ziemlich schlecht. Da wäre die erste Methode besser.

    Grüssli



  • ~john schrieb:

    Callbacks für C APIs müssen "extern C" definiert sein

    Ich weiß. Das Programm, was ich zeigte, war aber (komplett) ein C++ Programm. Es ging auch nur um das Prinzip. So ähnlich habe ich mir auch schon C++ LADSPA Plugins gebaut, die nur ein C Interface haben. Die wrapper-Funktionen müss dann natürlich C-Linkage besitzen.

    Gruß,
    SP



  • Sebastian Pizer schrieb:

    Liebe Mods, bitte löscht diesen und meinen vorangegangen Beitrag. Sie stiften nur Verwirrung nur.

    Erledigt.
    Du köntest natürlich dir einfach einen Account anlegen, das dauert nicht lang und es hat nur Vorteile - z.B. dass man seine Posts editieren kann 😉


Anmelden zum Antworten