how to avoid static member function when using gsl with c++
c++, c++11, callback, gsl, std-function
Solution
You can easily wrap member functions using the following code (which is a well known solution)
class gsl_function_pp : public gsl_function
{
public:
gsl_function_pp(std::function<double(double)> const& func) : _func(func){
function=&gsl_function_pp::invoke;
params=this;
}
private:
std::function<double(double)> _func;
static double invoke(double x, void *params) {
return static_cast<gsl_function_pp*>(params)->_func(x);
}
};
Then you can use std::bind to wrap the member function in a std::function. Example:
gsl_function_pp Fp( std::bind(&Class::member_function, &(*this), std::placeholders::_1) );
gsl_function *F = static_cast<gsl_function*>(&Fp);
However, you should be aware about the performance penalties of std::function before wrapping member functions inside gsl integration routine. See template vs std::function . To avoid this performance hit (which may or may not be critical for you), you should use templates as shown below
template< typename F >
class gsl_function_pp : public gsl_function {
public:
gsl_function_pp(const F& func) : _func(func) {
function = &gsl_function_pp::invoke;
params=this;
}
private:
const F& _func;
static double invoke(double x, void *params) {
return static_cast<gsl_function_pp*>(params)->_func(x);
}
};
In this case, to call a member function you need the following
Class* ptr2 = this;
auto ptr = [=](double x)->double{return ptr2->foo(x);};
gsl_function_pp<decltype(ptr)> Fp(ptr);
gsl_function *F = static_cast<gsl_function*>(&Fp);
PS: the link template vs std::function explains that compiler usually has an easier time optimizing templates than std::function (which is critical for performance if your code is doing heavy numerical calculation). So even tough the workaround in the second example seems more cumbersome, I would prefer templates than std::function.
Problem
I would like to use GSL within a c++ class without declaring member functions as `static`. The reason for this is because I don't know them too well and I'm not sure about thread safety. From what I read, `std::function` might be a solution but I'm not sure how to use it. My question comes down to how can I remove `static` in declaration of `g`? ``` #include<iostream> #include <functional> #include <stdlib.h> #include <gsl/gsl_math.h> #include <gsl/gsl_monte.h> #include <gsl/gsl_monte_plain.h> #include <gsl/gsl_monte_miser.h> #include <gsl/gsl_monte_vegas.h> using namespace std; class A { public: static double g (double *k, size_t dim, void *params) { double A = 1.0 / (M_PI * M_PI * M_PI); return A / (1.0 - cos (k[0]) * cos (k[1]) * cos (k[2])); } double result() { double res, err; double xl[3] = { 0, 0, 0 }; double xu[3] = { M_PI, M_PI, M_PI }; const gsl_rng_type *T; gsl_rng *r; ////// the following 3 lines didn't work /////// //function<double(A,double*, size_t, void*)> fg; //fg = &A::g; //gsl_monte_function G = { &fg, 3, 0 }; gsl_monte_function G = { &g, 3, 0 }; size_t calls = 500000; gsl_rng_env_setup (); T = gsl_rng_default; r = gsl_rng_alloc (T); { gsl_monte_plain_state *s = gsl_monte_plain_alloc (3); gsl_monte_plain_integrate (&G, xl, xu, 3, calls, r, s, &res, &err); gsl_monte_plain_free (s); } gsl_rng_free (r); return res; } }; main() { A a; cout <<"gsl mc result is " << a.result() <<"\n"; } ``` Update (1): I tried changing `gsl_monte_function G = { &g, 3, 0 };` to `gsl_monte_function G = { bind(&A::g, this,_1,_2,_3), 3, 0 };` but it didn't work Update (2): I tried using assigning std::function to a member function but it didn't work either. Update (3) in the end I wrote a non-member function: ``` double gmf (double *k, size_t dim, void *params) { auto *mf = static_cast<A*>(params); return abs(mf->g(k,dim,params)); //return 1.0; }; ``` It worked but it's a messy solution because I needed to write a helper function. With lambdas,function and bind, there should be a way to have everything logical within the class.