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.
You can easily wrap member functions using the following code (which is a well known solution)
Then you can use std::bind to wrap the member function in a std::function. Example:
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
In this case, to call a member function you need the following
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.
Why are you worried about the static function in this case? Variables and/or objects declared in a static function are not shared between different threads unless they are static themselves (which in your case they are not).
Is your code failing to do something?
Sorry, but what you're trying to do doesn't make any sense. Whatever thread safety issues you're worried about, they won't be solved by adding or removing the
static
keyword.The only reason why you would make
g
non-static would be if an instance ofA
was somehow required forg
's operation. And g's current implementation doesn't require such an instance.Note you can also make
g
a global function, without thestatic
keyword. There would be no visible difference in your case. However it's better style in your case to haveg
in the class which makes use of it, as a static function.Also, Here is some related material about pointers to (static/non-static) member functions.
GSL takes a C-type functions
“int (*)(char,float)”
rather than C++-type“int (Fred::*)(char,float)”
. To convert a member function to the C-type function, you need to addstatic
.see Is the type of “pointer-to-member-function” different from “pointer-to-function”?