5

通过使用 boost 或其他方式?

我想创建一个函数,d从(包括)索引 iStart 到索引 0 抓取双端队列的子集,进入一个新的双端队列,但也将这些值设置d为 0。我想到了这个:

std::deque<int> CreateSubset(std::deque<int>& d, int iStart )
{
   int iSubsetSize = iStart+1;
   std::deque<int> subset(iSubsetSize); // initialise a deque of a certain size.

   std::deque<int>::iterator it = d.begin();

   subset.assign (it, d.begin()+iStart+1);

   for(;it != d.begin()+iStart+2; it++)
   {
     *it = 0;
   }  
   return subset;
}

但这对我来说看起来很可怕-有更好的方法吗?

4

2 回答 2

9

这是我在 C++11 中的做法。我相信代码相当优雅,我不认为它有什么特别低效的地方:

#include <iostream>
#include <deque>
#include <iterator>
#include <algorithm>

template <typename ForwardIt>
std::deque<int> extract(ForwardIt from, ForwardIt to)
{
  using std::make_move_iterator;

  std::deque<int> d2(make_move_iterator(from),
                     make_move_iterator(to));
  std::fill(from,to,0);

  return d2;
}

函数模板采用extract()两个前向迭代器,将它们之间的内容移动到新创建的双端队列中,并将其设置为原始的 0。

所写的模板做了两个假设:

  1. 尽管源迭代器可以引用任何东西,但目标始终是双端队列;
  2. 您要将原始元素重置为的默认值是 0。

通过引入更多的模板参数或函数参数,可以放宽这两个假设。

如您所见,我使用std::make_move_iterator将输入迭代器转换为移动迭代器,从而导致元素被移动(而不是复制)到目的地。不过,只要这些是int,它就不会真正有所作为。

我使用std::fill算法将原始元素设置为 0。

这是您可以调用此函数模板的方式:

int main()
{
  /* Creating d. */
  std::deque<int> d
  { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 };

  /* Extracting the first three elements into a new deque. */
  auto d2 = extract(begin(d),begin(d) + 3);

  /* Printing the results. */    
  std::cout << "d:\n";
  for (const auto &elem : d)
    std::cout << elem << ',';

  std::cout << "\n\nd2:\n";
  for (const auto &elem : d2)
    std::cout << elem << ',';

  std::cout << std::endl;
  return 0;
}
于 2013-06-23T13:51:53.163 回答
3

由于容器概念需要定义容器类型,iterator甚至const_reference可以让 jogojapan 的答案更通用一点,而无需多个模板参数。

template <typename Container>
Container extract(typename Container::iterator from, 
                  typename Container::iterator to, 
                  typename Container::const_reference replacement)
{
  using std::make_move_iterator, std::fill;
  Container new_container(make_move_iterator(from),
                          make_move_iterator(to));
  fill(from,to,replacement);
  return new_container;
}

你可以去哪里

deque<int> d { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 };
auto d2 = extract<deque<int>>(begin(d),begin(d) + 3, 0);

缺点是模板参数推导不再那么好用了。

好处是您可以将代码用于几乎所有 STL 容器,例如vectors、deque、list、forward_list、set、map ...,因为它们都至少有一个forward_iterator 作为其迭代器类型。您还可以指定“默认”替换。

也可以使用指针而不是引用,这样您就可以决定是要擦除(传递 nullptr)还是用某个值替换元素(传递一个指向相应对象的有效指针)。

于 2013-06-24T01:30:56.247 回答