2

This is a very basic question and I'm sure this was answered before, but I don't know what to search for.

Stated I have a function that integrates a mathematical function:

double integrator(double (*func_to_integrate)(double,double));

But my function to integrate is of a type that allows me to manipulate more than two parameters, for example:

double func_to_integrate(double mu, double w0, double x, double y);

So that I can loop over different values of mu and w0 and compare the results of integration. How can I pass a function like func_to_integrate to integrator?

Greetings

Edit: As alain pointed out in the comments this is partly a duplicate of: How can currying be done in C++?

Is there an elegant solution doing a currying operation on a function pointer?

Community
  • 1
  • 1
Cukhen
  • 35
  • 3
  • 2
    When `integrator` calls `func_to_integrate`, what should the values of `mu` and `w0` be? You might want to look into [lambda functions](http://en.cppreference.com/w/cpp/language/lambda) or [`std::bind`](http://en.cppreference.com/w/cpp/utility/functional/bind) – Cornstalks Mar 06 '16 at 20:21
  • They should be some doubles I can manipulate in a loop. I tried lambda functions and bind. For both I wasn't able to create an object that integrator would accept. – Cukhen Mar 06 '16 at 20:25
  • Why your function and integrator do not return `double`? – Ivan Gritsenko Mar 06 '16 at 20:27
  • You are right, sorry. – Cukhen Mar 06 '16 at 20:29
  • 1
    You'll have to change the signature of `integrator`. With its current signature, the only thing you can do is make `mu` and `w0` globals instead of additional parameters. – Cornstalks Mar 06 '16 at 20:31
  • How do you "have" `integrator`? Do you have source? – Yakk - Adam Nevraumont Mar 06 '16 at 20:46
  • What you want to do is called "Currying". It's discussed in [this SO question](http://stackoverflow.com/questions/152005/how-can-currying-be-done-in-c), however I'm not sure if it works with function pointers. – alain Mar 06 '16 at 21:18
  • Thanks a lot! This is exactly what I was looking for. Seems it's only possible using . – Cukhen Mar 06 '16 at 21:27
  • I thought it was not a duplicate because you use a function pointer ;-) I voted to close it as duplicate now. – alain Mar 06 '16 at 21:36
  • I edited the question maybe there's a clever solution for function pointers. – Cukhen Mar 06 '16 at 21:43
  • Ok I retracted my close vote now. – alain Mar 06 '16 at 21:46

4 Answers4

2

Given you are able to change the signature of the integrator function, there are several solutions. The basic two directions are

  1. use a general template parameter instead of the function pointer (--where the caller has to be aware of the correct signature to pass), or
  2. use std::function<double(double, double)> as the function argument.

Both alternatives allow you to pass general function objects (functors, lambdas, a std::bind-object, etc.). I'd go with alternative 1. as it usually gives a better performance.

Then you can easily set up a lambda:

double mu = 1.0;
double w0 = 1.0;
auto f = [mu, w0] (double x, double y) { return func_to_integrate(mu, w0, x, y); };

and pass f to your (adusted) integrator routine.


Here is further an alternative if you cannot change the function signature -- as it is often the case for third-party libraries.

I first thought there is no solution in this case, as you can't bind a general functor to a function pointer. But then I encountered the nice idea in this answer (which I slightly adjusted): encode everything in terms of a static std::function variable, then use a static function to call this std::function object. As the static function is just syntactic sugar for a global function, it is possible to set up a function pointer to it:

template <typename Res, typename... Args>
struct function_ptr_helper
{
public:
    template<typename function_type>
    static auto bind(function_type&& f) { func = std::forward<function_type>(f); }

    static auto invoke(Args... args) { return func(args...); }
    static auto* ptr() { return &invoke; }

private:
    static std::function<Res(Args ...)> func;
};

template <typename Res, typename... Args>
std::function<Res(Args ...)> function_ptr_helper<Res, Args...>::func;

template <typename Res, typename ... Args>
auto* get_function_ptr(std::function<Res(Args...)> f)
{
    using type = function_ptr_helper<Res, Args...>;

    type::bind(std::move(f));
    return type::ptr();
}

DEMO

You can use it as

double mu = 1.0;
double w0 = 1.0;
std::function<double(double, double)> f
    = [mu, w0] (double x, double y) { return func_to_integrate(mu, w0, x, y); };

integrator(get_function_ptr(f));

Be aware, however, that you are dealing with global variables here. This often works, but sometimes might lead to subtle errors (for example when you call get_function_ptr more than once in a single expression).

Community
  • 1
  • 1
davidhigh
  • 14,652
  • 2
  • 44
  • 75
1

How can I pass a function like func_to_integrate to integrator?

Seems very easy to fix. Just add two more arguments to your pointer function signature.

double integrator(double (*func_to_integrate)(double,double,double,double));
Ivan Gritsenko
  • 4,166
  • 2
  • 20
  • 34
0

As previous comments point out the most elegant solution would be using bind and or lambda. A nice solution would be an adapter design pattern class wrapper, where mu and w0 become class members.

class IntegratorAdaptor {
  private:
    double _mu, double _w0;

  public:
    IntegratorAdapter(double arg_mu, double arg_w0)
    : _mu(arg_mu), _w0(arg_w0) { }

    double twoArgIntegrator( double x, double y )
      { return func_to_intergrate( _mu, _w0, x, y ); }
};

Construction of this class is very low overhead, so I made the members immutable. I didn't come up with very good names for the class and functions, you should put more thought into those names than I did.

Chip Grandits
  • 317
  • 1
  • 9
0

Most answers I've seen for this kind of question rely on std::function and/or C++ templates. I wanted to share an alternate solution which may be less general, but to me is simpler. It doesn't use std::function or templates---in fact, it doesn't use any libraries at all.

The idea is that instead of passing around a function pointer, you pass around an object that implements a particular 'interface'. In this example,

double integrator(double (*func_to_integrate)(double,double))

becomes

double integrator(Integratable func_to_integrate)

where Integratable is an 'interface' (abstract base class) defined as

class Integratable {
public:    
    virtual double compute(double x, double y) = 0;  // pure virtual function
}

We can then make func_to_integrate into an instance of this class, with extra members for the additional parameters:

class SomeClassName : public Integratable {
public:
    double compute(double x, double y);
    double mu;
    double w0;
}

SomeClassName func_to_integrate;

To test several values of mu and w0 in a loop:

for(double mu : mus) {
    for(double w0 : w0s) {
        func_to_integrate.mu = mu;
        func_to_integrate.w0 = w0;
        integrator(func_to_integrate);
    }
}

Of course, we have to modify integrator so that instead of calling a function pointer, it calls the compute() method on the object passed to it, but this is trivial (assuming you can change the signature of integrator, which is probably required for any possible solution to this problem).

I like this solution because it avoids some of C++'s more heavyweight features and libraries. However, it certainly is less general than many of the other solutions that are often suggested for partial application in C++. For OP I believe this solution is an elegant fit for the given use case.

Craig D.
  • 51
  • 4