Reputation: 659
This question seems to have been asked numerous times before, for example here1, here2 and here3.
What I am trying to do is, set the member function
of the C-Struct gsl_function
to a member function of my class.
class MyClass{
double foo(double x)
{
return ...;
}
double bar(double x)
{
...
gsl_function F;
// Problem I cant do this (compiler error)
F.function = &(this->foo);
}
};
The third link above provides a solution, I think it is based on the wrapper approach described here4.
So my question is can I do better. Is there an easier way? For example, possibly by using Boost's function and Bind objects.
I am weighing up the option of using a gsl wrapper, such as o2scl. But am a bit releuctant as I may pay the price later if the wrapper is not well maintained. Any suggestions?
Upvotes: 2
Views: 753
Reputation: 9039
Since GSL allows you to pass in arbitrary parameters, you can abuse this to hold the pointer to the instance under question. Then use a static member function to forward to the member function:
class MyClass
{
double foo(double x)
{
...
}
static double foo_wrapper(double x, void *params)
{
return static_cast<MyClass*>(params)->foo(x);
}
double bar(double x)
{
...
gsl_function F;
F.function=&MyClass::foo_wrapper;
F.params=this;
// invoke GSL function passing in F
...
}
};
Can you do better? Is there an easier way? Not really. Any approach you take will be doing this under the covers somewhere.
But you can write a simple wrapper which hides some of this:
class gsl_function_pp : public gsl_function
{
public:
gsl_function_pp(boost::function<double(double)> const& func) : _func(func)
{
function=&gsl_function_pp::invoke;
params=this;
}
private:
boost::function<double(double)> _func;
static double invoke(double x, void *params)
{
return static_cast<gsl_function_pp*>(params)->_func(x);
}
};
This should give you (possibly at a moderate performance penalty due to multiple indirections involved) the type of functionality you'd want:
class MyClass
{
double foo(double x)
{
...
}
double bar(double x)
{
gsl_function_pp F(boost::bind(&MyClass::foo, this, _1));
// invoke GSL function passing in F
...
}
};
The caveat is that you'll have to ensure that any gsl_function_pp
object stays in scope for the entire time that the GSL might invoke it. So, don't try to set up a root finder/etc in one function (using a local gsl_function_pp), return, and then perform root finding iterations in another -- you'll get a crash or worse.
Upvotes: 7