将lambda传递给数值库

Pass lambda to numerical library

本文关键字:lambda      更新时间:2023-10-16

我试图使用一个数值积分库,它要求我将double (*f)(double,void*)作为参数传递给它。我怎么能传递它一个lambda我创建在同一范围内?我试着

auto myLambda = [&](double d, void* data) { ... }

,但lambda的类型不能转换为标准库要求的类型。有解决办法吗?

感谢您的宝贵时间!
template<class T>using type=T;
template<class F>
struct callback_t {
  F data;
  void* pdata(){return &data;}
  template<class R, class...Args>
  operator type<R(*)(Args...,void*)>()const{
    return [](Args...args,void*pdata)->R{
      F* data=static_cast<F*>(pdata);
      return (*f)(std::forward<Args>(args)...);
    };
  }
};
template<class F>
callback_t<F> callback(F f){
  return{std::move(f)};
}

使用:

int scale=3;
auto cb = callback([&](double d){return d*scale;});

则传递cb代替函数指针,传递cb.pdata()代替void*参数。

想必这个库还允许您传入data参数,用于调用所提供的函数。在这种情况下,您可以定义一个包装器,将该参数视为指向您想要调用的实际对象的指针,并将调用转发到该对象,可能像这样:

template <class F>
double function_for_library(double d, void* data) {
    F& f = *static_cast<F*>(data);
    return f(d);
}

现在,如果你有一个F类型的任意函数对象f,你可以像这样调用库:

invoke_library(function_for_library<F>, &f); // implicit conversion to void*

对于lambda,你必须使用decltype,但这没什么大不了的。

auto myLambda = /* ... */;
invoke_library(function_for_library<decltype(myLambda)>, &myLambda);

或者您可以编写另一个包装器来推断该类型

只有没有捕获的lambda 才能衰变成函数指针

我怀疑void*是传递用户数据的方式。所以你必须创建一个struct

struct Functor
{
    explicit Functor(capture_t&);
    void operator()(double d)
    {
         // Your stuff
    }
    static void call(double d, void* userdata)
    {
        (*reinterpret_cast<Functor*>(userdata))(d)
    }
private:
    capture_t m_capture
};

然后调用

Functor func(capture);
library_function(&Functor::call, &func);