Численное интегрирование лямбда-функции с gsl

Я работаю с 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>'

2

Решение

Ответ @ 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);
3

Другие решения

Только лямбды без перехватов могут быть преобразованы в указатели функций.

[Expr.prim.lambda]

6 Тип замыкания для неуниверсального лямбда-выражения с нет
лямбда-захват
имеет открытый не виртуальный не явный констант преобразование
функция указатель на функцию
с языковой связью C ++ (7.5), имеющей
тот же параметр и возвращаемый тип, что и у функции типа замыкания
позвонить оператору

По сути, это означает, что

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

действует так, как если бы оно было определено как

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

если лямбда имеет перехват, функция преобразования не определена, и лямбда не может быть преобразована в обычный указатель функции.

2

По вопросам рекламы [email protected]