Passing a C++ Lambda to a GSL Function

Date:2017-06-10

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.