Matteo Monti
Matteo Monti

Reputation: 8960

Numerical integration of lambda function with gsl

I am working with gsl to integrate a function. That function is built in a lambda function that has as input a double and a void *, and as output a double. Now, everything works fine if I use the lambda without any variable capture. But if I do variable capturing, it doesn't work any more.

Could anyone explain me why so?

Here are two snippets of code that I made up to explain my problem:

This one works fine:

int main(int argc, char **argv)
{

    double beg = 0;
    double end = 10;

    auto f = [] (double x, void * p) {return 2.0;};

    gsl_integration_workspace * w = gsl_integration_workspace_alloc (GSL_INTEGRATION_WORKSPACE_SIZE);

    double result;
    double error;

    gsl_function F;
    F.function = f;
    F.params = NULL;

    gsl_integration_qags (&F, beg, end, 0, GSL_INTEGRATION_RELATIVE_PRECISION, GSL_INTEGRATION_WORKSPACE_SIZE, w, &result, &error);

    cout<<result<<endl;

}

While this one

int main(int argc, char **argv)
{

    double beg = 0;
    double end = 10;

    double p = 2.0;

    auto f = [&] (double x, void * p) {return p;};

    gsl_integration_workspace * w = gsl_integration_workspace_alloc (GSL_INTEGRATION_WORKSPACE_SIZE);

    double result;
    double error;

    gsl_function F;
    F.function = f;
    F.params = NULL;

    gsl_integration_qags (&F, beg, end, 0, GSL_INTEGRATION_RELATIVE_PRECISION, GSL_INTEGRATION_WORKSPACE_SIZE, w, &result, &error);

    cout<<result<<endl;

}

Yields on the line

F.function = f;

the following error:

Assigning to 'double (*)(double, void *)' from incompatible type '<lambda at /[omissis]/main.cpp>'

Upvotes: 2

Views: 1350

Answers (2)

Vivian Miranda
Vivian Miranda

Reputation: 2485

The answer given by @user657267 is correct. That is why a small wrapper is needed to convert lambas with capture to gsl_function.

Here is the wrapper for the f gsl_function and Here is the wrapper for the fdf gsl_function

You can convert lambda functions to gsl_function after using the wrapper proposed in these two answers in the following way (I haven't invented the version with std::function, it was a well known answer. The template version I haven't seen before my answer).

// std::function version
double a = 1;
gsl_function_pp Fp([=](double x)->double{return a*x;}); 
gsl_function *F = static_cast<gsl_function*>(&Fp); 

//template version
double a = 1;
auto ptr = [=](double x)->double{return a*x;};
gsl_function_pp<decltype(ptr)> Fp(ptr);
gsl_function *F = static_cast<gsl_function*>(&Fp); 

Upvotes: 4

user657267
user657267

Reputation: 21000

Only lambdas without captures can be converted to function pointers.

[expr.prim.lambda]

6 The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual non explicit const conversion function to pointer to function with C++ language linkage (7.5) having the same parameter and return types as the closure type’s function call operator.

Essentially what this means is that

[] (double, void*) {return 2.0;};

acts as though it were defined as

class Lambda
{
public:
  double operator()(double, void*);
  operator double(*)(double, void*)() const;
};

if the lambda has a capture however the conversion function is not defined, and the lambda cannot be converted to a regular function pointer.

Upvotes: 3

Related Questions