Passing a function template as argument to another function template is always a bit tricky. Typically one has to resort to creating a lambda object that goes and calls the original function.
Example
template <typename It>
void f(It, It) {}
void g(std::vector<int>::iterator, std::vector<int>::iterator) {}
template <typename C, typename F>
void callA(C&& c, F callable) {
return callable(std::begin(c), std::end(c));
}
Problem
If I have a std::vector<int> c
, I cannot just pass f
along to callA
because f
is a template and not a function:
callA(c, f); // f has an unresolved overloaded function type and cannot be deduced
callA(c, std::distance); // same problem
callA(c, g); // works because g is a proper function, not a template
callA(c, [](auto a, auto b) {return f(a,b);}); // works again
Even if we help deduce the type of the callable:
template <typename C, template <typename> typename F,
typename T = std::decay_t<decltype(std::begin(std::declval<C>()))>>
auto callB(C&& c, F<T> callable) {
return callable(std::begin(c), std::end(c));
}
this fails to compile.
Question
Is there a way to force C to deduce the function's type directly without resorting to a lambda function or type-erasure like std::function
? Effectively, (how) can I turn a function template into a first-class citizen? That is, have its type deduced.
I'm willing to go to some lengths when defining the higher-order function (see callB
versus callA
), but not when calling it.
CodePudding user response:
You can change the parameter type to function pointer, which could be converted from function template (with template argument deduced). E.g.
template <typename C>
void callA(C&& c, void(*callable) (std::decay_t<decltype(std::begin(std::declval<C>()))>, std::decay_t<decltype(std::begin(std::declval<C>()))>)) {
return callable(std::begin(c), std::end(c));
}
Then
std::vector<int> c;
callA(c, f); // template argument It will be deduced as std::vector<int>::iterator for f
CodePudding user response:
Are you aware of BOOST_HOF_LIFT
?
It allows you to lift overloaded and/or templated functions into objects with as easy syntax as auto my_max = BOOST_HOF_LIFT(std::max);
.
You could change callA(c, std::distance)
to callA(c, BOOST_HOF_LIFT(std::distance))
.