Я работаю с gsl, чтобы интегрировать функцию. Эта функция встроена в лямбда-функцию, которая имеет на входе double и void *, а на выходе — double.
Теперь все работает нормально, если я использую лямбду без захвата переменных. Но если я делаю захват переменных, это больше не работает.
Может ли кто-нибудь объяснить мне, почему так?
Вот два фрагмента кода, которые я составил, чтобы объяснить мою проблему:
Этот работает нормально:
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;
}
Пока этот
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;
}
Урожай на линии
F.function = f;
следующая ошибка:
Assigning to 'double (*)(double, void *)' from incompatible type '<lambda at /[omissis]/main.cpp>'
Ответ @ user657267 правильный. Вот почему для преобразования lambas с перехватом в gsl_function необходима небольшая оболочка.
Вот обертка для функции f gsl_function а также Вот обертка для функции fdf gsl_function
Вы можете преобразовать лямбда-функции в gsl_function после использования оболочки, предложенной в этих двух ответах, следующим образом (я не придумал версию с std :: function, это был хорошо известный ответ. Версию шаблона, которую я раньше не видел мой ответ).
// 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);
Только лямбды без перехватов могут быть преобразованы в указатели функций.
[Expr.prim.lambda]6 Тип замыкания для неуниверсального лямбда-выражения с нет
лямбда-захват имеет открытый не виртуальный не явный констант преобразование
функция указатель на функцию с языковой связью C ++ (7.5), имеющей
тот же параметр и возвращаемый тип, что и у функции типа замыкания
позвонить оператору
По сути, это означает, что
[] (double, void*) {return 2.0;};
действует так, как если бы оно было определено как
class Lambda
{
public:
double operator()(double, void*);
operator double(*)(double, void*)() const;
};
если лямбда имеет перехват, функция преобразования не определена, и лямбда не может быть преобразована в обычный указатель функции.