简体   繁体   English

&#39;std :: function之间的转换 <double(double)> &#39;至&#39;double(*)(double)&#39;

[英]Conversion between 'std::function<double(double)>’ to ‘double (*)(double)’

I am trying to pass a custom lambda to a function that expects a function pointer (more precisely the zero function in Brent library ). 我试图将自定义lambda传递给需要函数指针的函数(更确切地说是Brent库中zero函数)。

The idea is that I would create the lambda once with the parameters and then it would be evaluated at several values x inside this function. 我的想法是,我将使用参数创建一次lambda,然后在该函数内部将其评估为多个值x

I have tried the steps in this thread with no success and I am getting an error of no known conversion for argument 4 from 'Function {aka std::function<double(double)>}' to 'double (*)(double)' . 我尝试了该线程中的步骤,但未成功,并且出现no known conversion for argument 4 from 'Function {aka std::function<double(double)>}' to 'double (*)(double)'错误no known conversion for argument 4 from 'Function {aka std::function<double(double)>}' to 'double (*)(double)' As far as I understand the compiler does not know how to cast from those 2 types. 据我了解,编译器不知道如何从这两种类型进行转换。

Is there a workaround around this error? 是否有解决此错误的方法? It would be better if no modifications had to be made to the library and it could be solved within my program. 如果不必对库进行任何修改,并且可以在我的程序中解决该问题,那就更好了。 Here is a snippet of code to show the problem. 这是显示该问题的代码段。

# include <functional>
# include "brent.hpp"

using namespace brent;

typedef std::function<double(double)> Function;

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

int main ( )

{
  Function func = function_builder ( 2.0, -1.0 );
  double z = zero (0, 1, 0.001, func ); //func should be a function pointer of type double (*)(double)

  return 0;
}

In your case, your lambda function has state - the captured a, b variables. 在您的情况下,您的lambda函数具有状态-捕获的a,b变量。 There is no way to convert a stateful lambda to a pointer to function, but... 无法将有状态的lambda转换为函数的指针,但是...

The Brent library does not expect a pointer to function. Brent库不希望指针起作用。 The zero function is declared as: zero函数声明为:

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

and has an overload defined as: 并具有以下定义的重载:

// 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);
}

But you should use the first variant for your needs, which expects: 但是您应该根据需要使用第一个变体,该变体可以期望:

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

which is good news, since you simply have to derive from func_base, and put a lambda in there: 这是个好消息,因为您只需要从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 );
    });
}

The implementation details are a bit ugly, but the usage is reasonable: 实现细节有些丑陋,但用法合理:

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;
}

Of course, it is possible to get rid of the lambda function altogether, and to manage state inside a non-templated object. 当然,有可能完全摆脱lambda函数,并管理非模板对象内部的状态。 But on the other hand, inheriting from lambda makes it easy to define many other function builders such as: 但是另一方面,从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  );
  });
}

In fact, you can use function_builder_base directly everywhere, eliminating the need for a function_builder middleman. 实际上,您可以在任何地方直接使用function_builder_base ,而无需使用function_builder中间人。

You won't have much luck without ugly hack (like using a global object of sorts) of passing a std::function<double(double)> to a double(*)(double) . 如果没有将std::function<double(double)>传递给double(*)(double)丑陋技巧(例如使用各种全局对象),您将不会很幸运。 The key difference is that function pointer genuinely only abstract stateless functions while std::function<double(double)> or lambda functions with non-empty capture contain state. 关键区别在于,函数指针真正只能仅抽象无状态函数,而带有非空捕获的std::function<double(double)>或lambda函数则包含状态。

Specifically for the Brent library mentioned there is , however, a way! 特别是对于布伦特图书馆提到的 ,然而,一个办法! The library doesn't really take function pointer but travels in terms of func_base objects. 该库并没有真正使用函数指针,而是根据func_base对象传播。 You can get one of these with a simple adapter: 您可以使用简单的适配器获得其中之一:

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); }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 错误“没有从 &#39;std::vector 进行的已知转换<double, std::allocator<double> &gt;&#39; 到 &#39;double *&#39; ” 使用 std::count_if() 时? - Error “ no known conversion from 'std::vector<double, std::allocator<double> >' to 'double *' ” when using std::count_if()? 铸造 std::complex<double> 作为双 - Casting std::complex<double> as double 是否存在从double到std :: array的隐式转换的方法 <double,1> ? - Is there a way for implicit conversion from double to std::array<double,1>? 未定义模板&#39;std :: __ 1 :: function的隐式实例化 <int (double, double, double, double)> “ - Implicit instantiation of undefined template 'std::__1::function<int (double, double, double, double)>' 将std :: accumulate中的double转换为int转换警告 - double to int conversion warning in std::accumulate 初始化std :: pair <double,std :: array <std :: pair <double,double>,3 >> - Initialising std::pair<double, std::array<std::pair<double, double>, 3> > &quot;+=&quot; 操作在 std::complex 类型之间不起作用<double>和 __complex__ 双 - "+=" operation not working between types std::complex<double> and __complex__ double C中双**和双(*)[2]之间的差异 - Difference between double ** and double (*)[2] in C 在float和double之间键入NaN的转换 - Type conversion of NaN between float and double 字符串始终转换为双精度0 - String to double conversion allways 0
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM