So i'm trying to write an Integration function to be used with c++11 lambdas. The code looks something like this:
double Integrate(std::function<double(double,void*)> func, double a,double b,std::vector<double> & params)
{
gsl_integration_workspace * w = gsl_integration_workspace_alloc (1000);
gsl_function F;
F.function =func;
F.params = (void*)¶ms;
double error,result;
gsl_integration_qag (&F, a, b, 0, 1e-7, 1000,GSL_INTEG_GAUSS61,w, &result, &error);
gsl_integration_workspace_free (w);
return result;
}
void Another_function()
{
//...
Integrate([](double a,void* param)
{
return ((vector<double> *)params)->at(0)*a+((vector<double> *)params)->at(1);
}
,0,3,{2,3});
}
Trying to compile this, compiler says:
error: cannot convert ‘std::function<double(double, void*)>’ to ‘double (*)(double, void*)’ in assignment
about line
F.function =func;
But if I write:
F.function =[](double a,void* param)
{
return ((std::vector<double> *)param)->at(0)*a+((std::vector<double> *)param)->at(1);
};
It compiles and works fine. How should I solve this?
Looks like the gsl library requires a function pointer. A lambda which does not capture can be converted to a function pointer. Any lambda can be converted to a
std::function
. But astd::function
cannot be converted to a function pointer.You could try:
A
std::function<>
cannot be converted to a function pointer.std::function<>
are function objects that can potentially hold state while regular functions are stateless (kind of, you could potentially havestatic
variables, but that is a different thing).On the other hand, stateless lambdas can be converted to a function pointer, so you could potentially change the signature of your function to take a function pointer directly and the lambda will be converted:
Note that it is illegal to bind an rvalue to a non-const reference, so you cannot legally pass
{2,3}
as the last argument toIntegrate
(even if Visual Studio allows you to), you will need to create a named variable.It's best to encapsulate the
void *
conversion inside your wrapper function:There is a certain amount of excess indirection here (through
std::function
) but the CPU's branch predictor will be able to perform well as the indirection will always be to the same lambda.Using a void* is typical of C callback interfaces to pass some "state" to the function. However, std::function does not need this because std::function supports "stateful functions". So, you could do something like this:
and store a reference to the parameter vector as part of the functor that will be encapsulated in the std::function object or do something like this:
However, this solution would use rather many indirections. GSL would invoke your lambda. Your lambda would invoke the std::function<>::operator() which in turn would inwoke some kind of virtual function that is used for type erasure which would in turn invoke the actual computation.
So, if you care about performance, you could get rid of a couple of layers there, specifically std::function. Here's a another approach with a function template:
I guess I would prefer this over the std::function solution.
If you need to integrate a lambda function with capture (in this case there is no conversion to raw pointer), and if you don't want to have the performance penalties associated with std::function ( as pointed out by sellibitze - see std::function vs template), you can use the following wrapper
Here is a test code that shows how to use it
If you really want to use std::function, then you can use this version of the wrapper
The test code in this case is even simpler
The nice thing about those wrapper is that they can also be used to integrate class member functions.