lambda函数与gsl的数值积分

Numerical integration of lambda function with gsl

本文关键字:数值积分 gsl 函数 lambda      更新时间:2023-10-16

我正在使用gsl来集成一个函数。该函数内置于lambda函数中,该函数的输入为double和void*,输出为double。现在,如果我在没有任何变量捕获的情况下使用lambda,一切都很好。但如果我进行变量捕获,它就不再有效了。

有人能解释一下为什么吗?

以下是我为解释我的问题而编写的两段代码:

这个很好用:

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给出的答案是正确的。这就是为什么需要一个小包装器来将带有捕获的lambda转换为gsl_function。

这是f gsl_function的包装器,这是fdf gsl_function的包装器

使用这两个答案中提出的包装器后,您可以通过以下方式将lambda函数转换为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); 

只有没有捕获的lambda才能转换为函数指针。

[expr.prim.lambda]

6具有no的非泛型lambda表达式的闭包类型lambda捕获具有公共非虚拟非显式常量转换函数到指向函数的指针,带有C++语言链接(7.5)与闭包类型的函数相同的参数和返回类型呼叫接线员。

本质上,这意味着

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

就好像它被定义为

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

如果lambda有一个捕获,但是没有定义转换函数,并且lambda不能转换为常规函数指针。