我可以在这里使用模板特化或类型强制转换吗?

Can I use template specialization or type coercion here?

本文关键字:类型 转换 在这里 我可以      更新时间:2023-10-16

我有一个用于将慢函数映射到集合的现有模板(以同名clojure函数的风格),我想在这篇有用的博客文章中使用"move semantics"来加速: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语句),但像这样的类型转换让我感到不安。对于如何解决这个问题或为重写情况添加专门化模板有什么建议吗?

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);
}