boost::iterator_adapter не работает с алгоритмами STL

Рассмотрим следующий итератор «туда и обратно», который пытается перебрать все элементы в коллекции, в конечном итоге снова перебирая первый элемент в качестве последнего шага:

#include <boost/iterator/iterator_adaptor.hpp>

template<typename IteratorBase>
class roundtrip_iterator 
     : public boost::iterator_adaptor< 
          roundtrip_iterator<IteratorBase>, // the derived class overriding iterator behavior
          IteratorBase,                     // the base class providing default behavior
          boost::use_default,               // iterator value type, will be IteratorBase::value_type
          std::forward_iterator_tag,        // iterator category
          boost::use_default                // iterator reference type
       > 
{
private:
  IteratorBase m_itBegin;
  IteratorBase m_itEnd;
  bool m_complete;

public:
  roundtrip_iterator( IteratorBase itBegin, IteratorBase itEnd ) 
    : iterator_adaptor_(itBegin), m_itBegin(itBegin), m_itEnd(itEnd), m_complete(false)
  {}

  void increment()
  { 
    if( m_complete )
    {
      base_reference() = m_itEnd;
      return;
    }

    ++base_reference();

    if(base_reference() == m_itEnd)
    {
      base_reference() = m_itBegin;
      m_complete = true;
    }
  }
};

Я только реализовал приращение на данный момент.

В нынешнем виде итератор, кажется, хорошо работает в стандартных циклах for, но я не могу заставить его работать с алгоритмами STL. Например:

int main(int argc, char *argv[])
{
  std::vector<int> v;

  v.push_back(1);
  v.push_back(2);
  v.push_back(3);

  roundtrip_iterator<std::vector<int>::iterator> roundtrip(v.begin(), v.end());

  for( ; roundtrip.base() != v.end(); ++roundtrip)
    std::cout << *roundtrip << std::endl;

  std::cout << std::endl;

  roundtrip_iterator<std::vector<int>::iterator> roundtrip2(v.begin(), v.end());

  std::for_each(
    roundtrip2.base(), v.end(),
    print);

}

Отпечатки:

1
2    
3
1 // First element printed out using standard for loop.

1
2
3 // The for_each algo stops here for some reason.

Есть ли у кого-нибудь идеи о разнице между ними?


person JimmidyJoo    schedule 18.08.2012    source источник


Ответы (1)


Вызывая roundtrip2.base(), вы фактически передаете диапазон от [v.begin(), v.end) до std::for_each. Вы должны быть в состоянии создать значение e с одним прошедшим концом, чтобы вместо него можно было передать [roundtrip2, e).

person Luc Danton    schedule 18.08.2012
comment
Поэтому я пошел с вызовом std::for_each(roundtrip2, roundtrip2.end()). Это, очевидно, включало создание конечного метода на самом адаптере, который возвращал константную ссылку фиктивному адаптеру, прошедшему конец. Не уверен, что это стандартная идиома или правильный способ сделать это, но это работает. Мне также пришлось определить пользовательские операторы == и !=. Большое спасибо. - person JimmidyJoo; 18.08.2012