是否有一种优雅的方式将一个deque的子集转移到另一个deque?

时间:2013-06-23 13:30:44

标签: c++ deque

或许以其他方式使用提升?

我想创建一个函数,从索引iStart中获取deque d的子集到索引0,转换为新的deque,同时在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;
}

但这对我来说太可怕了 - 有更好的方式吗?

2 个答案:

答案 0 :(得分:7)

以下是我在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. 虽然源迭代器可以引用任何东西,但目标始终是deque;
  2. 要将原始元素重置为的默认值为0。
  3. 通过引入更多模板参数或函数参数,可以放宽这两个假设。

    如您所见,我使用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;
    }
    

答案 1 :(得分:3)

由于Container概念要求容器类型定义iteratorconst_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容器的代码,例如vector,deque,list,forward_list,set,map ......因为它们至少都有一个forward_iterator作为它们的迭代器类型。 您还可以指定“默认”替换。

也可以使用指针而不是引用,以便您可以决定是否要擦除(传递nullptr)或用特定值替换元素(将有效指针传递给相应的对象)。