如何避免类似模板中的代码重复

时间:2015-05-28 09:00:51

标签: c++ templates c++11

我实现了一个parallel_accumulate,类似于std :: acumulate但是使用线程来并行化累积工作。 有两个版本的std :: accumulate,第二个带有一个额外的运算符用于累积,而第一个隐式假设添加..第一个版本:

template<typename Iterator, typename T>
static T parallel_accumulate(Iterator first, Iterator last, T init)
{
  unsigned long const length = std::distance(first, last);
  if (!length) return init;

  unsigned long const max_ths = 64;
  unsigned long const hw_ths = std::thread::hardware_concurrency();
  unsigned long const num_ths = std::min(hw_ths != 0 ? hw_ths : 2, max_ths);
  unsigned long const block_size = length / num_ths;
  std::vector<T> results(num_threads);
  std::vector<std::thread> threads(num_ths);
  Iterator block_start = first;

  for (unsigned long i = 0; i < num_ths; ++i) {
      Iterator block_end = block_start;
      std::advance(block_end, block_size);
      threads[i] = std::thread(                                 // diff1
                        _noop<Iterator,T>(),
                        block_start,
                        block_end,
                        std::ref(results[i]));
      block_start = block_end;
  }
  std::for_each(threads.begin(), threads.end(),std::mem_fn(&std::thread::join));

  return std::accumulate(results.begin(), results.end(), init); // diff2
}

第二版:

template<typename Iterator, typename T, typename BinOp>
static T parallel_accumulate(Iterator first, Iterator last, T init, BinOp op)
{
  unsigned long const length = std::distance(first, last);
  if (!length) return init;

  unsigned long const max_ths = 64;
  unsigned long const hw_ths = std::thread::hardware_concurrency();
  unsigned long const num_ths = std::min(hw_ths != 0 ? hw_ths : 2, max_ths);
  unsigned long const block_size = length / num_ths;
  std::vector<T> results(num_threads);
  std::vector<std::thread> threads(num_ths);
  Iterator block_start = first;

  for (unsigned long i = 0; i < num_ths; ++i) {
      Iterator block_end = block_start;
      std::advance(block_end, block_size);
      threads[i] = std::thread(                                     // diff1
                        _op<Iterator,T,BinOp>(),
                        block_start,
                        block_end,
                        std::ref(results[i]));
      block_start = block_end;
  }
  std::for_each(threads.begin(), threads.end(),std::mem_fn(&std::thread::join));

  return std::accumulate(results.begin(), results.end(), init, op); // diff2
}

您可以很容易地看到我的两个版本的实现仅在两行上有所不同,我如何避免在C ++中优雅地复制此代码(即不使用#defines)?

(请注意,为了清楚起见,我省略了_noop和_op,它们只是调用各个版本的std :: accumulate的可调用结构)

更新:希望拥有第一个没有显式添加运算符的版本(因为隐式std :: accumulate更快)。

1 个答案:

答案 0 :(得分:4)

如果你有C ++ 14透明操作符仿函数,那么第一个版本可以实现为

template<typename Iterator, typename T>
static T parallel_accumulate(Iterator first, Iterator last, T init)
{
    return parallel_accumulate(first, last, init, std::plus<>());
}

如果不这样做,则等同于std::plus<>只是

struct my_plus {
    template<class T, class U>
    auto operator()(T&& t, U&& u) const -> decltype(std::forward<T>(t) + std::forward<U>(u)) {
        return std::forward<T>(t) + std::forward<U>(u);
    }
};