C ++: pass a function with an arbitrary number of parameters as a parameter

long time browser, first time here. I wrote several scripts to execute various 1D methods of numerical integration and compiled them into a library. I would like this library to be as flexible as possible that it is able to integrate.

Here I include an example: a very simple example of a trapezoidal rule in which I pass a pointer to a function to be integrated.

// Numerically integrate (*f) from a to b // using the trapezoidal rule. double trap(double (*f)(double), double a, double b) { int N = 10000; double step = (ba)/N; double s = 0; for (int i=0; i<=N; i++) { double xi = a + i*step; if (i == 0 || i == N) { s += (*f)(xi); } else { s += 2*(*f)(xi); } } s *= (ba)/(2*N); return s; } 

This works great for simple functions that take only one argument. Example:

 double a = trap(sin,0,1); 

However, sometimes I may need to integrate something that has more parameters, such as a quadratic polynomial. In this example, the coefficients will be determined by the user before integration. Code example:

 // arbitrary quadratic polynomial double quad(double A, double B, double C, double x) { return (A*pow(x,2) + B*x + C); } 

Ideally, I could do something like this to integrate it:

 double b = trap(quad(1,2,3),0,1); 

But it is clear that this does not work. I ran into this problem by defining a class that has coefficients as members and a function of interest as a member function:

 class Model { double A,B,C; public: Model() { A = 0; B = 0; C = 0; } Model(double x, double y, double z) { A = x; B = y; C = z; } double func(double x) { return (A*pow(x,2)+B*x+C); } }; 

However, then my integration function must change to take an object as an input instead of a function pointer:

 // Numerically integrate model.func from a to b // using the trapezoidal rule. double trap(Model poly, double a, double b) { int N = 10000; double step = (ba)/N; double s = 0; for (int i=0; i<=N; i++) { double xi = a + i*step; if (i == 0 || i == N) { s += poly.func(xi); } else { s += 2*poly.func(xi); } } s *= (ba)/(2*N); return s; } 

This works fine, but the resulting library is not very independent, since it requires a specific class model. In addition, ideally, the Model should be able to change from user to user, so I do not want to fix it in the header file. I tried using functional templates and functors to make this work, but it is not very independent, since again the template must be defined in the header file (if you do not want to explicitly create instances, but it is not).

So, to summarize: is there a way to make my integration functions accept arbitrary 1D functions with a variable number of input parameters, while remaining independent enough to be compiled into a standalone library? Thanks in advance for the suggestions.

+8
c ++ functor templates function-pointers
source share
2 answers

You need templates and std::bind() (or its boost::bind() if you cannot afford C ++ 11). For example, this will be your trap() function:

 template<typename F> double trap(F&& f, double a, double b) { int N = 10000; double step = (ba)/N; double s = 0; for (int i=0; i<=N; i++) { double xi = a + i*step; if (i == 0 || i == N) { s += f(xi); } // ^ else { s += 2* f(xi); } // ^ } s *= (ba)/(2*N); return s; } 

Please note that we generalize function pointers and allow passing any type of called objects (including, for example, C ++ 11 lambda). Therefore, the syntax for calling a user-provided function is not *f(param) (which only works for function pointers), but just f(param) .

As for flexibility, consider two hard-coded functions (and pretend to be significant):

 double foo(double x) { return x * 2; } double bar(double x, double y, double z, double t) { return x + y * (z - t); } 

Now you can provide both the first function directly in the input of trap() and the result of binding the last three arguments of the second function to a specific value (you have a free choice on which arguments to bind):

 #include <functional> int main() { trap(foo, 0, 42); trap(std::bind(bar, std::placeholders::_1, 42, 1729, 0), 0, 42); } 

Of course, you can get even more flexibility with lambdas:

 #include <functional> #include <iostream> int main() { trap(foo, 0, 42); trap(std::bind(bar, std::placeholders::_1, 42, 1729, 0), 0, 42); int x = 1729; // Or the result of some computation... int y = 42; // Or some particular state information... trap([&] (double d) -> double { x += 42 * d; // Or some meaningful computation... y = 1; // Or some meaningful operation... return x; }, 0, 42); std::cout << y; // Prints 1 } 

And you can also pass your own tp trap() state functors or some callable objects wrapped in a std::function object (or boost::function if you cannot afford C ++ 11). The selection is pretty wide.

Here is a living example .

+8
source share

What are you trying to do is make it possible

 trap( quad, 1, 2, 3, 0, 1 ); 

With C ++ 11 we have an alias pattern and a variation pattern

 template< typename... Ts > using custom_function_t = double (*f) ( double, Ts... ); 

the above define a custom_function_t , which take a double and a variable number of arguments.

so your trap function will become

 template< typename... Ts > double trap( custom_function_t<Ts...> f, Ts... args, double a, double b ) { int N = 10000; double step = (ba)/N; double s = 0; for (int i=0; i<=N; i++) { double xi = a + i*step; if (i == 0 || i == N) { s += f(xi, args...); } else { s += 2*f(xi, args...); } } s *= (ba)/(2*N); return s; } 

Using:

 double foo ( double X ) { return X; } double quad( double X, double A, double B, double C ) { return(A*pow(x,2) + B*x + C); } int main() { double result_foo = trap( foo, 0, 1 ); double result_quad = trap( quad, 1, 2, 3, 0, 1 ); // 1, 2, 3 == A, B, C respectively } 

Tested on Apple LLVM 4.2 Compiler.

+3
source share

All Articles