(If you are ready to use variable macros, scroll to the end of this answer to see the best answer that makes everything completely variable. But I think variable macros are just a g ++ extension.)
This can be done to work if you are ready to specify the function name at the end of the parameter list. Putting it later, the compiler can infer the necessary types from earlier parameters in doit
:
cout << doit(7, 6, sumall) << endl; cout << doit(10, sumall) << endl;
Here is the daemon on ideone .
The disadvantage is that for each number of parameters you need to implement one doit. I only implemented it for one- and two-parameter functions, but this should not be a problem for its extension:
int sumall(int a) { return a; } int sumall(int a, int b) { return a+b; } template<typename A1, typename A2, typename R> auto doit( A1 a1, A2 a2, R (*f) (A1,A2)) -> R { return f(a1, a2); } template<typename A1, typename R> auto doit( A1 a1, R (*f) (A1)) -> R { return f(a1); }
Update: Sometimes it may seem that you can avoid using f
as the first argument. But it is not as strong as putting it in the end. Consider an example where where are two functions that take the same number of arguments, but different types of parameters. eg:.
int sumall(int a, int b) { return a+b; } string sumall(string a, string b) { return a+" "+b; }
You need to have a function as the last argument, so that the template output can use the type and number of parameters at the beginning to derive the argument types. Here's a demo on the idea of function-arg first and function-arg last .
The only drawback is that the end of the arg argument is that we cannot use variable patterns — the variable arg packages must be at the end. And you have to choose the types correctly - see how I had to use string("hi")
instead of just "hi"
.
Using Variadic Macros to Have the Best of All Worlds
By implementing doit
as a macro and using variable macros (gcc / g ++ extension), it is possible to have a completely variational solution with the first function name. Demo on ideone .
cout << doit(sumall, 7, 6) << endl; cout << doit(sumall, 10) << endl; cout << doit(sumall, string("hi"), string("world")) << endl;
Using decltype
and a couple of other simple classes, we can use the arguments provided to output the argument types, and then he can use this to select the correct method from the overload set and infer the return type from that.
template<typename ...Args> struct OverloadResolved { template<typename R> static auto static_doit( R (*f) (Args...), Args ... args ) -> R { return f(args...); } }; template<typename ...Args> auto deduce(Args...) -> OverloadResolved<Args...> { return OverloadResolved<Args...>(); } template<typename T> struct dummy : public T { }; #define doit(f, ...) ( dummy<decltype(deduce( __VA_ARGS__ ))> :: static_doit(f, __VA_ARGS__) )
I am sure that it is a safe use of macros, nothing will be evaluated twice (in fact, nothing is executed inside decltype
.