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?
Given you are able to change the signature of the integrator
function, there are several solutions. The basic two directions are
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();
}
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).