Problem beim umgehen eines pointer-to-member-function's



  • Hallo erst einmal,

    ich bin noch etwas grün hinter den Ohren was das Programieren angeht, aber ich muss da halt durch.
    Also ich versuche ein "ROOT-Programm" in ein C++ Programm zu überführen. Dabei ist das aktuelle Problem folgendes:
    SetFCN mag keinen pointer-to-member-function sonder nur pointer-to-function. Deshalb versuche ich nun die member-function in eine globale Funktion einzupacken.

    // main.cpp
    
    int main(int argc, char** argv) {
    
        B_Class* B_p = new B_Class();   
        B_Class* ptr;
        B_p->setup(ptr);
    
        A_Class* A_p = new A_Class();
        A_p->fa(ptr);
    
        return (EXIT_SUCCESS);
    }
    
    //A_Class.cpp
    
    extern "C"  void wrap(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag);
    
    void wrap(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
    {
        ptr->fb(npar, gin, f, par, iflag);               //  ***** Fehler *****
    }    
    
    void A_Class::fa(B_Class* ptr)
    {
          TMinuit *gMinuit = new TMinuit(7);
          gMinuit->SetFCN(wrap);    
    }
    
    // B_Class.cpp
    
    void B_Class::fb(Int_t &, Double_t *, Double_t &, Double_t *, Int_t )
    {
        x=p;  // hier eigentlich wilde Funktionen
    }
    
    void B_Class::setup(B_Class* ptr)
    {
        ptr = this;
    }
    

    Fehlermeldung:

    A_Class.cpp:21: error: ‘ptr’ was not declared in this scope
    

    Mir ist eigentlich klar, DASS 'ptr' dort nicht "sichtbar" ist, aber ich weiß nicht wie ich das ändern kann.
    warp() und fb() müssen unbedingt diese Parameter haben und keine anderen.
    In meiner Anfängernaivität hab unter anderem überlegt so etwas zu machen wie:

    wrap(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag ,B_Class ptr😉

    das geht aber nicht weil SetFCN nur folgendes erwartet:

    //  virtual void	SetFCN(void* fcn)
    //  virtual void	SetFCN(void (*)(Int_t&, Double_t*, Double_t&f, Double_t*, Int_t) fcn)
    

    So nun hoffe ich erst einmal, dass es eine Lösung gibt, zweites dass ihr sie wisst und mir schreibt und drittens dass ich das dann auch umsetzen kann.



  • Okay, also so wie ich das verstehe möchtest Du einer Funktion, die einen Funktionszeiger erwartet, einen Methodenzeiger übergeben. Das funktioniert so leider nicht. Du kannst auch keinen Zeiger auf die Klasse "reinschmuggeln". Das Einzige, was mir einfällt, sind globale Variablen, die Du vor dem Aufruf änderst.

    B_Class* currentBClass;
    
    void wrap(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
    {
        currentBClass->fb(npar, gin, f, par, iflag);               //  ***** Fehler *****
    } 
    
    int main(/*...*/)
    {
    BClass bClass1, bClass2;
    
    currentBClass = &bClass1;
    wrap(/*...*/);
    currentBClass = &bClass2;
    wrap(/*...*/);
    }
    

    Hilft Dir das etwas weiter? Evtl. kannst Du uns auch ein paar Rahmeninformationen geben, damit wir Dir zu einem besseren Design oder so raten können. "ROOT-Programm" sagt mir erstmal nichts.



  • Hallo Eisflamme,
    danke für deine Hilfe!
    mit ROOT-Programm meine ich:
    http://en.wikipedia.org/wiki/ROOT

    Schade das es da keinen anderen Trick gibt, "reinschmuggeln" hätte mir gefallen. *g*

    Ich hab das mit der globalen Variable hinbekommen und es läuft so wie ich es mir vorstelle.
    Danke noch mal!

    Hier "meine Lösung" für andere Suchende.

    "main.cpp"
    
    #include <stdlib.h>
    #include "A_Class.h"
    #include "B_Class.h"
    
    B_Class* ptr_global;
    
    int main(int argc, char** argv) {
    
        B_Class* B_p = new B_Class();   
        B_Class* ptr;
        B_p->setup(ptr);
        ptr_global=ptr;
        A_Class* A_p = new A_Class();
        A_p->fa();
    
        return (EXIT_SUCCESS);
    }
    
    "A_Class.h"
    #ifndef _A_CLASS_H
    #define	_A_CLASS_H
    #include "B_Class.h"
    
    class A_Class {
    public:
        A_Class();
        A_Class(const A_Class& orig);
        virtual ~A_Class();
        void fa();
    private: 
    };
    #endif	/* _A_CLASS_H */
    
    "A_Class.cpp"
    #include "A_Class.h"
    #include <stdlib.h>
    #include <iostream>
    #include "B_Class.h"
    #include "TROOT.h"
    #include "TMinuit.h"
    
    double x=2;
    double p=3;
    
    extern B_Class* ptr_global;
    
    extern "C"  void wrap(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag);
    
    void wrap(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
    {
        ptr_global->fb(npar, gin, f, par, iflag);
    }    
    
    A_Class::A_Class(){
    
    }
    
    A_Class::A_Class(const A_Class& orig) {
    }
    
    A_Class::~A_Class() {
    }
    
    void A_Class::fa()
    {
          TMinuit *gMinuit = new TMinuit(7);
          gMinuit->SetFCN(wrap);
          std::cout << "fa() done" << std::endl;   
    }
    
    "B_Class.h"
    #ifndef _B_CLASS_H
    #define	_B_CLASS_H
    #include "TROOT.h"
    
    class B_Class {
    public:
        B_Class();
        B_Class(const B_Class& orig);
        virtual ~B_Class();
        void fb(Int_t &, Double_t *, Double_t &, Double_t *ar, Int_t );
        void setup(B_Class*);
    private:
    };
    #endif	/* _B_CLASS_H */
    
    "B_Class.cpp"
    extern double x;
    extern double p;
    
    B_Class::B_Class() {
    }
    
    B_Class::B_Class(const B_Class& orig) {
    }
    
    B_Class::~B_Class() {
    }
    
    void B_Class::fb(Int_t &, Double_t *, Double_t &, Double_t *, Int_t )
    {
        x=p;       // irgend eine Funktion halt
    }
    
    void B_Class::setup(B_Class* ptr)
    {
        ptr = this;
    }
    

    Hier noch ein mal Schlagwörter:
    virtual void SetFCN(void* fcn)
    virtual void SetFCN(void ()(Int_t&, Double_t, Double_t&f, Double_t*, Int_t) fcn)



  • rangernumber1 schrieb:

    Schade das es da keinen anderen Trick gibt, "reinschmuggeln" hätte mir gefallen. *g*

    Gibt es, ist aber nicht portierbar, und auch nicht ganz einfach.
    Nennt sich "thunk".
    Kannst mal danach googeln.

    Das Prinzip dahinter ist dynamisch Code für eine Funktion zu generieren, die an eine andere Funktion weiterleitet, und dabei einen zusätzlichen Parameter übergibt.
    Der Wert für den zusätzlichen Parameter wird dabei zur Laufzeit an die Thunk-Erzeuger-Funktion übergeben. Und der Wert wird dabei nicht in einer globalen Variable gespeichert, sondern ist Teil des "Thunks". Dadurch kann man mehrere solche "Thunks" mit unterschiedlichen Werten gleichzeitig haben & verwenden. Und wenn man den "Thunk" nimmer braucht, löscht man ihn einfach.

    In deinem Fall wäre der zusätzliche Parameter dein "ptr".

    Und den so generierten "Thunk" setzt man dann als Callback-Funktion.

    Leider kenne ich keine Library/Framework mit der/dem man so einen Thunk halbwegs einfach erzeugen könnte.


Anmelden zum Antworten