Reputation: 8960
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
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
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