I have been trying to get a templated function to call a set of similar functions to avoid boilerplate.
FooA(float a, Widget* w);
FooB(int b, Widget* w);
FooC(int c, Widget* w);
FooD(int d, int e, Widget* w);
template <typename... Args>
static void RunFoo(void (*foo)(Args..., Widget*), Args... args) {
Widget w
foo(args, &w);
}
I don't understand why this works fine with:
float a = 10;
RunFoo(FooA, a);
But it fails whenever I try with multiple arguments:
int a = 10;
int b = 3;
RunFoo(FooD, a, b);
It fails to compile with the error: "candidate template ignored: failed template argument deduction"
Is this beyond the capabilities of c++ templates?
template<class T>struct tag {using type=T;};
template<class Tag>using type_t=typename Tag::type;
template<class T>using block_deduction=type_t<tag<T>>;
template <typename... Args>
static void RunFoo(block_deduction<void(*)(Args...,Widget*)> foo, Args... args) {
Widget w
foo(args, &w);
}
you cannot deduce like Args..., Widget*
-- parameter packs must be last in general.
Both cases are "equal" in deduction. block_deduction
prevents deduction from occurring on that parameter. So the other deduction happens, and works.
Note that such deduction is usually a bad idea. You don't want to deduce one parameter, and generate a function pointer elsewhere. It is brittle.
This might be better:
template <class F, class... Args>
static std::result_of_t<F(Args..., Widget*)> RunFoo(F&& f, Args&&... args) {
Widget w
return std::forward<F>(f)(std::forward<Args>(args)..., &w);
}
if you are passing an overload set in, wrap the overload set up in an overload set object. std::result_of_t<?>
is C++14, replace with typename std::result_of<?>::type
in C++11.