Passing a C++ Lambda to a GSL Function
The GNU Scientific Library is a C library that offers (among other things) an
integration routine. One does not pass a simple double (*f)(double)
function
parameter because there might be additional parameters needed. The article
Currying in C lists various possibilities, the GSL
implements the variant with the void *
. A dummy implementation of this
integration routine could look like this, for the purpose of this article:
double gsl_integrate(double (*f)(double, void *), void *param) { std::cout << f(1.0, param) << std::endl; return 0.0; }
This is not the real function! The real thing is more complicated but is not directly needed to understand this approach.
We would like to pass a C++ lambda into this function. That is not directly possible because the types do not match. Therefore it would be great to have some wrapping mechanism that allows to call it with C++ lambdas, function pointers and functors.
The idea is to pass the lambda as the void *
and use a general function for
the parameter f
. The following unwrapping function has the signature required
by the GSL function but can unwrap a C++ lambda:
double unwrap(double x, void *p) { auto fp = static_cast<std::function<double(double)> *>(p); return (*fp)(x); }
Using this, one can write an integration function that takes a C++ lambda and passes that to the GSL function:
double integrate(std::function<double(double)> ftor) { return gsl_integrate(unwrap, &ftor); }
In the user code, this might be used with a lambda that captures something:
int main(int argc, char **argv) { double b = 5.4; auto func = [&b](double x) { return x * x + b; }; integrate(func); }
For the actual GSL function, one needs to define a struct
and a little more
elaborate wrapper. This should be enough to get you started.