【问题标题】:Can I use template specialization or type coercion here?我可以在这里使用模板专业化或类型强制吗?
【发布时间】:2016-01-18 17:37:12
【问题描述】:

我有一个现有的模板,用于将慢速函数映射到集合(以同名的 clojure 函数的样式),我想用“移动语义”来加速这个有用的博客文章的风格,而不是我: http://blog.knatten.org/2012/11/02/efficient-pure-functional-programming-in-c-using-move-semantics/

我写的这段旧代码很适合我:

template <typename function,
      template <typename...> class collection,
      typename in_type,
      typename... types,
      typename out_type = 
        typename std::result_of<function(in_type)>::type>
static collection<out_type> pmap(
  const function& f, const collection<in_type, types...>& c)  {
  collection<out_type> result;
  if(!c.empty())  {
    result = collection<out_type>(c.size());   
    __gnu_parallel::transform(c.cbegin(),c.cend(),result.begin(),f);
  }
  return result;
}

既然我愿意放弃输入集合,我应该能够在 in_type 与 out_type 相同的情况下通过重写 c 而不是分配一个全新的集合来加快这一速度。我尝试了模板专业化,但编译器在特殊情况下无法选择,我无法提出修复。这是我尝试的一些技巧:

template <typename function,
      template <typename...> class collection,
      typename in_type,
      typename... types,
      typename out_type = 
        typename std::result_of<function(in_type)>::type>
static collection<out_type> pmap(
  const function& f, const collection<in_type, types...>&& c)  {
  collection<out_type> result;
  if(!c.empty())  {
    if(typeid(in_type)==typeid(out_type))  {
      __gnu_parallel::transform(c.begin(),c.end(),c.begin(),f);
      result = c;
    }
    else  {
      result = collection<out_type>(c.size());
      __gnu_parallel::transform(c.cbegin(),c.cend(),result.begin(),f);
    }
  }
  return std::move(result);
}

我猜有一些 hack 会让编译器接受 result=c(尽管它不应该因为周围的 if 语句而在意),但是这样的转换让我感到不安。有关如何解决此问题或为覆盖案例添加专业化模板的任何建议?

【问题讨论】:

    标签: c++ functional-programming c++14 move-semantics rvalue-reference


    【解决方案1】:

    typeid 是一个运行时构造,因此您尝试在运行时而不是编译时选择行为。

    您可以编写两个重载并使用std::enable_if 选择正确的一个:

    template <typename function,
          template <typename...> class collection,
          typename in_type,
          typename... types,
          typename out_type = 
            typename std::result_of<function(in_type)>::type,
          typename std::enable_if<!std::is_same<in_type, out_type>::value>::type* = nullptr>
    static collection<out_type> pmap(
      const function& f, collection<in_type, types...>&& c)  {
      collection<out_type> result;
      result.reserve(c.size());
      __gnu_parallel::transform(c.cbegin(),c.cend(),std::back_inserter(result),f);
    
    
      return result;
    }
    
    template <typename function,
          template <typename...> class collection,
          typename in_type,
          typename... types,
          typename out_type = 
            typename std::result_of<function(in_type)>::type,
          typename std::enable_if<std::is_same<in_type, out_type>::value>::type* = nullptr>
    static collection<out_type,types...> pmap(
      const function& f, collection<in_type, types...>&& c)  {
      __gnu_parallel::transform(c.begin(),c.end(),c.begin(),f);
    
      return std::move(c);
    }
    

    【讨论】:

    • 谢谢,您的 enable_if 示例让我继续前进。我不确定你是否可以在没有移动语义的情况下做到这一点......看来你在第二部分中正在写一个 const & ,我从未尝试过。
    • 哦,对不起,如果你想修改c,你需要一个非常量引用(甚至是一个右值引用)。
    • 您也错过了返回类型的types...。您也可以通过引用返回。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-25
    • 2021-04-12
    • 2014-10-08
    • 1970-01-01
    • 1970-01-01
    • 2021-07-08
    • 1970-01-01
    相关资源
    最近更新 更多