1

I am trying to pass a custom lambda to a function that expects a function pointer (more precisely the zero function in Brent library).

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.

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)’. 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;
}
Jesús Ros
  • 480
  • 2
  • 6
  • 19
  • You can't convert directly. Make a global/static `std::function`, and make a regular function (or stateless lambda) that calls it. Then pass the regular function as function pointer. – HolyBlackCat Aug 20 '18 at 13:11
  • The linked library explicitly supports c++ functors, but hand-rolled them. See `class func_base{ public: virtual double operator() (double) = 0; };` – MSalters Aug 20 '18 at 13:17
  • 1
    What solution from that question have you tried, and how has it not worked? You are just asking a duplicate question saying that the duplicate's answers didn't work for you which isn't enough to provide an answer. You need to provide more information. – François Andrieux Aug 20 '18 at 13:18

2 Answers2

3

In your case, your lambda function has state - the captured a, b variables. There is no way to convert a stateful lambda to a pointer to function, but...

The Brent library does not expect a pointer to function. The zero function is declared as:

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:

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. But on the other hand, inheriting from lambda makes it easy to define many other function builders such as:

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.

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33
1

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). 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.

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. 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); }
};
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380