Search code examples
c++functionc++11curryingreduction

Pass a function of n arguments as function of n-x arguments


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?


Solution

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