函数模板可以用作高阶函数调用中的一等公民吗?

bit*_*ask 5 c++ templates first-class-functions language-lawyer higher-order-functions

将函数模板作为参数传递给另一个函数模板总是有点棘手。通常,人们必须创建一个 lambda 对象来调用原始函数。

例子

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));
}
Run Code Online (Sandbox Code Playgroud)

问题

如果我有一个std::vector<int> c,我不能直接传递f给callA因为f是一个模板而不是一个函数:

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
Run Code Online (Sandbox Code Playgroud)

即使我们帮助推断可调用的类型:

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));
}
Run Code Online (Sandbox Code Playgroud)

这无法编译。

问题

有没有办法强制 C++ 直接推导函数的类型,而不需要借助 lambda 函数或类型擦除之类的std::function?实际上,(如何)我可以将函数模板变成一等公民?即推导其类型。

在定义高阶函数时(请callB参阅与),我愿意付出一定的努力callA,但在调用它时则不愿意。

son*_*yao 3

您可以将参数类型更改为函数指针,该函数指针可以从函数模板转换(推导模板参数)。例如

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));
}
Run Code Online (Sandbox Code Playgroud)

然后

std::vector<int> c;
callA(c, f); // template argument It will be deduced as std::vector<int>::iterator for f
Run Code Online (Sandbox Code Playgroud)

居住