Calling GSL function inside a class in a shared library

前端 未结 2 897
时光说笑
时光说笑 2020-12-18 13:15

I\'m trying make a shared library in c++ implementing tools for Fermi gases. I\'m using the GSL library to solve a function numerically and my code runs without a problem wi

2条回答
  •  难免孤独
    2020-12-18 13:57

    It is indeed interesting that people ask this over and over again. One reason may be that the proposed solutions are not easy to understand. I for one had problems understanding and implementing them. (the solutions did not work out of the box for me, as you might expect.)

    With the help of tlamadon I just figured out a solution that may be helpful here as well. Let's see what you guys think.

    So just to recap, the problem is that you have a class that contains a member function on which you want to operate with something from the GSL library. Our example is useful if the GSL interface requires a

    gsl_function F;
    

    see here for a definition.

    So here is the example class:

    class MyClass {
    
        private:
            gsl_f_pars *p;  // not necessary to have as member
    
        public: 
            double obj(double x, void * pars);  // objective fun
            double GetSolution( void );  
            void setPars( gsl_f_pars * xp ) { p = xp; };
            double getC( void )  ;  // helper fun
    
    };
    

    The objective of this exercise is to be able to

    1. initiate MyClass test,
    2. supply it with a paramter struct (or write a corresponding constructor), and
    3. call test.GetSolution() on it, which should return whatever the GSL function was used for (the minimum of obj, a root, the integral or whatever)

    The trick is now to put have an element in the parameter struct gsl_f_pars which is a pointer to MyClass. Here's the struct:

    struct gsl_f_pars {
        double a;
        double b;
        double c;
        MyClass * pt_MyClass;
    };
    

    The final piece is to provide a wrapper that will be called inside MyClass::GetSolution() (the wrapper is a stand in for the member function MyClass::obj, which we cannot just point to with &obj inside the class). This wrapper will take the parameter struct, dereference pt_MyClass and evaluate pt_MyClass's member obj:

    // Wrapper that points to member function
    // Trick: MyClass is an element of the gsl_f_pars struct
    // so we can tease the value of the objective function out
    // of there.
    double gslClassWrapper(double x, void * pp) {
        gsl_f_pars *p = (gsl_f_pars *)pp;
        return p->pt_MyClass->obj(x,p);
    }
    

    The full example is a bit too long to post here, so I put up a gist. It's a header file and a cpp file, it should be working wherever you have GSL. Compile and run with

    g++ MyClass.cpp -lgsl -o test
    ./test
    

提交回复
热议问题