【问题标题】:C++ can't derive template parameters for high-order functionsC++ 不能为高阶函数派生模板参数
【发布时间】:2019-01-20 20:02:07
【问题描述】:

当我使用接受另一个函数作为参数的模板函数时,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)。

【问题讨论】:

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


    【解决方案1】:

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

    但是在这种情况下,不需要指定返回类型。返回类型扣除可以做的工作:

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

    【讨论】:

      【解决方案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;auto ... -&gt; decltype(f(source)) 在 C++11 中)。

      -- 编辑--

      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&amp; x) { ... }

      正确。 因为 std::function 模板类型不能从 generic-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。

      【讨论】:

      • 这个解决方案的好处是我可以在函数内部使用T(例如,如果我想实现vector_map)。缺点是由于某种原因我现在不能在函数调用中写[] (const auto&amp; x) { ... }
      • @dyukha - 回答改进:希望这会有所帮助
      猜你喜欢
      • 1970-01-01
      • 2019-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多