C++ 无法为高阶函数派生模板参数

C++ can't derive template parameters for high-order functions

当我使用接受另一个函数作为参数的 have 模板函数时,C++ 无法派生模板参数。一直指定它们非常烦人。如何定义以下函数,这样我就不必每次都指定类型参数?

#include <functional>

template <typename S, typename T>
T apply(const S& source, const function<T (const S&)>& f) {
  return f(source);
}

template <typename S, class Functor, typename T>
T applyFun(const S& source, const Functor& f) {
  return f(source);
}

int main() {
  // Can't derive T. Why?
  apply(1, [](int x) { return x + 1; });
  // Compiles
  apply<int, int>(1, [](const int& x) { return x + 1; });
  // Can't derive T. Kind of expected.
  applyFun(1, [](int x) { return x + 1; });
}

为什么它不能在第二个函数中导​​出类型参数,但在第一个函数中却不能(因为 x + 1int,所以它应该推断出 T = int).

模板参数必须出现在函数参数类型中才能扣除。此外,lambda 不是函数,因此 return 类型的 lambda 不能参与模板参数推导。

但在这种情况下,不需要指定return类型。 Return 类型推导可以完成这项工作:

template <typename S, class Functor>
auto applyFun(const S& source, const Functor& f) {
  return f(source);
  }

如果可以使用 C++17,则可以使用 std::function 的推导指南,如下所示

template <typename S, typename F,
          typename T = typename decltype( std::function{std::declval<F>()} )::result_type>
T applyFun (S const & source, F const & f)
 {  
   return f(source);
 }

但是,正如 Oliv 所指出的,对于您的示例函数,不需要 T 因为您可以使用 auto (来自 C++14;auto ... -> decltype(f(source)) 在 C+ +11).

-- 编辑--

OP 说

The good thing about this solution is that I can use T inside the function (e.g. if I want to implement vector_map).

您可以检测并使用 T,也在函数内部,使用 using

有点像

template <typename S, typename F>
auto applyFun (S const & source, F const & f)
 {  
   using T = typename decltype( std::function{f} )::result_type;

   return f(source);
 }

或更简单:using T = decltype( f(source) );.


OP 还观察到

The downside is that for some reason now I can't write [] (const auto& x) { ... } in function call.

正确。 因为 std::function 无法从泛型 lambda 中推导出模板类型。

但是使用你知道参数类型的事实,你可以再次使用 decltype()

template <typename S, typename F,
          typename T = decltype(std::declval<F const>()(std::declval<S const>()))>
T applyFun (S const & source, F const & f)
 { return f(source); }

此解决方案也适用于 C++14 和 C++11。