Memberfunctionpointer als Functionpointer verwenden



  • Suchst du boost::bind?



  • Binder aus der STL???



  • zeronull schrieb:

    @groovemaster: mir ist inzwischen leider auch klar, dass es zwar syntaktisch funktioniert, es aber an der Semantik scheitert ..

    @phlox81: mir ist immer noch nicht ganz klar, was du meinst. Es scheitert doch immer noch daran, dass ich keinen Memberfunktionspointer einer Funktion übergeben kann, die einen Funktionspointer erwartet?!

    wenn du keinen MethodenZeiger aber einen FunktionsZeiger übergeben kannst,
    dann gebe einen Funktionszeiger mit, der an einen MethodenZeiger weiterleitet.
    Den MethodenZeiger musst du dir dann in der Funktion besorgen, Übergeben
    geht nicht, entweder du machst dir ein struct mit einen statischen MethodenZeiger,
    oder du legst eine Klasse an, welche diesen hält, und implementierst diese als Singelton.



  • Klingt vernünftig .. 😉
    thx phlox81



  • Der Union-Kram ist übrigens nicht legal. Du darfst nur auf das zuletzt zugewiesene Element der Union zugreifen. Zugriff auf ein nicht zuletzt(!) zugewiesenes Element ist undefiniert. Unions sind dazu da Speicherplatz zu sparen (von Sinn/Sinnlosigkeit heutzutage bitte absehen), nicht um zu casten!



  • 7H3 N4C3R schrieb:

    Der Union-Kram ist übrigens nicht legal. Du darfst nur auf das zuletzt zugewiesene Element der Union zugreifen. Zugriff auf ein nicht zuletzt(!) zugewiesenes Element ist undefiniert.

    Nein.

    union value
    {
        float as_float;
        long as_int;
    };
    
    value a;
    a.as_float = 1.5;
    cout << a.as_int;
    

    ist völlig legal und definiert. Mal abgesehen davon, dass float uU eine andere Speichergrösse als long hat. Spielt hier aber keine Rolle, es geht um's Prinzip.

    Die Undefiniertheit bei zeronull liegt vielmehr darin, dass der Aufbau eines Member-Funktionszeigers nicht definiert ist. Wenn man also Non-Member-Funktionszeiger und Member-Funktionszeiger auf die selbe Speicherstelle schreibt, ist nicht garantiert, dass die eigentlichen Adresswerte sich überdecken. Zudem bleibt das Problem mit this, was dann interessant wird, wenn virtuelle Funktionen ins Spiel kommen.



  • Aber irgendwas war da mit der Zugriffsreihenfolge. Hat HumeSikkins mal was drüber geschrieben soweit ich mich erinnern kann.



  • Vielleicht hat Hume gemeint, dass es undefiniert ist, wenn sich die Member nicht exakt überdecken. Womit wir beim Thema von nicht initialisiertem Speicher wären.
    ZB ist

    union vaule
    {
        char c;
        wchar_t w;
    };
    
    value a;
    a.c = 'a';
    wcout << a.w;
    

    In der Tat undefiniert.



  • Problematisch sind auch Konstruktor/Destruktor-Aufrufe. Welcher Destruktor soll denn aufgerufen werden, wenn mehrere Klassentypen in der Union sind? Welche wurden überhaupt konstruiert?
    Für native Datentypen sollte es an sich kein Problem sein. Wüsste spontan aber nicht, dass der Standard hierfür eine Ausnahme macht. Und außerdem: Es gibt extra den reinterpret_cast, wenn man solche Schweinereien will.

    Edit: direkt ausm Standard (9.5):
    In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time.

    Danach kommt zwar noch eine Ausnahme, wenn die Unions mehrere POD-Structs enthalten, die eine gemeinsame initiale Sequenz an Datentypen haben, spielt hier aber keine Rolle.
    Typen in Unions dürfen zwar keine nicht-trivialen Konstruktoren/Destruktoren haben (was mein Beispiel entschärft), trotzdem sagt der Standard exakt, dass nur ein Datentyp aktiv sein kann.



  • Um nochmal auf das angegebene problem zurückzukommen... Wenns echte c-callbacks sind helfen dir funktoren natürlich nicht weiter. Aber ein ordentliches callback sieht einer meinung nach so aus:

    typedef void (*callback_ptr)(void*);
    //und nicht so:
    typedef void (*fcbptr)();
    

    Wenn du also ein "ordentliches" callback hast, könnte dir folgendes klässchen behilflich sein:

    template<class T,class callback_arg=void*>
    struct access_callback
    {
        template<class R,R (T::*mfptr>
        R callback_fn(callback_arg a)
        {
            return (reinterpret_cast<T*>(a).*mfptr)();    //reinterpret_cast, weil a nicht void* sein muss
        };
    
        template<void (T::*mfptr)>            //nur ne abkürzung
        void callback_fn(callback_arg a)
        {
            (reinterpret_cast<T*>(a).*mfptr)();
        };
    };
    

    Davon leitest du dann ab und übergibst dem callback eine instanz von callback_fn.


Anmelden zum Antworten