C ++无法导出高阶函数的模板参数

时间:2019-01-20 20:02:07

标签: c++ c++11 templates template-deduction type-deduction

当我使用具有接受另一个函数作为参数的模板函数时,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,所以应该推论{{1} }。

2 个答案:

答案 0 :(得分:4)

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

但是在这种情况下,无需指定返回类型。返回类型演绎可以完成这项工作:

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

答案 1 :(得分:2)

如果您可以使用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;在C ++ 11中为auto ... -> decltype(f(source)) )。

-编辑-

OP说

  

此解决方案的优点是我可以在函数内部使用T(例如,如果我想实现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也观察到

  

缺点是由于某种原因,我现在无法在函数调用中编写[] (const auto& x) { ... }

正确。 因为无法从通用lambda推断出std::function模板类型。

但是根据您知道参数类型的事实,您可以再次使用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。