从“ std :: function <double(double)>”到“ double(*)(double)”之间的转换

时间:2018-08-20 13:09:04

标签: c++

我试图将自定义lambda传递给需要函数指针的函数(更确切地说是Brent library中的=TEXT(DATE(2018,7,1),"mm/dd/yyyy")函数)。

我的想法是,我将使用参数创建一次lambda,然后在该函数内以多个值zero对其进行评估。

我尝试了此thread中的步骤,但没有成功,并且出现了x错误。据我了解,编译器不知道如何从这两种类型进行转换。

是否有解决此错误的方法?如果不必对库进行任何修改,并且可以在我的程序中解决该问题,那就更好了。这是显示此问题的代码段。

no known conversion for argument 4 from ‘Function {aka std::function<double(double)>}’ to ‘double (*)(double)’

2 个答案:

答案 0 :(得分:2)

在您的情况下,您的lambda函数具有状态-捕获的a,b变量。无法将有状态的lambda转换为函数的指针,但是...

Brent library不需要指向功能的指针。 zero函数声明为:

double zero ( double a, double b, double t, func_base& f )

并具有以下过载定义:

// This is the overload you asked about, but....
double zero ( double a, double b, double t, double f ( double x ) ){
  func_wrapper foo(f);
  return zero(a, b, t, foo);
}

但是您应该使用第一个变体来满足您的需求,

class func_base{
 public:
   virtual double operator() (double) = 0;
};

这是个好消息,因为您只需从func_base派生,然后在其中放一个lambda:

template <class Lambda>
class FunctionWithState : public func_base, public Lambda {
  public:
     FunctionWithState(const Lambda & lambda): Lambda(lambda) {}
     double operator()(double x) override 
     { return Lambda::operator()(x); }
};

template<class Lambda>
auto function_builder_base (Lambda lambda)
{
    return FunctionWithState<decltype(lambda)>(lambda);
}

auto function_builder(double a, double b)
{
    return function_builder_base([a,b](double x) {
        return ( a * x + b );
    });
}

实现细节有些丑陋,但用法合理:

main ( )
{
  // func must be "auto" because the type depends on lambda, whose type is unknown.
  auto func = function_builder ( 2.0, -1.0 );
  double z = zero (0, 1, 0.001, func );
  return 0;
}

当然,有可能完全摆脱lambda函数,并可以管理非模板对象内部的状态。但是另一方面,从lambda继承可以轻松定义许多其他函数构建器,例如:

auto function_builder3(double a, double b, double c)
{
  return function_builder_base([a,b,c](double x) {
       return ( a*x*x + b*x + c  );
  });
}

实际上,您可以在任何地方直接使用function_builder_base,而无需function_builder中间人。

答案 1 :(得分:1)

如果没有将std::function<double(double)>传递给double(*)(double)的丑陋骇客(例如使用各种全局对象),您将不会很幸运。关键区别在于,函数指针真正只能仅抽象无状态函数,而具有非空捕获的std::function<double(double)>或lambda函数则包含状态。

特别是对于提到的Brent库,这里是 ,但是,有一种方法!该库实际上并没有使用函数指针,而是根据func_base对象进行传递。您可以使用简单的适配器获得其中之一:

struct brent_fun: func_base {
    std::function<double(double)> fun;
    template <typename Fun>
    explicit brent_fun(Fun&& fun): fun(std::move(fun)) {}
    double operator()(double value) override { return this->fun(value); }
};