Пользовательский итератор не работает с BOOST_FOREACH?

#boost #iterator

#boost #итератор

Вопрос:

У меня есть класс, который содержит некоторые данные, и я хотел бы добавить функции begin() и end() , которые предоставляют итераторы по идентификаторам данных.

Я использую Boost counting_iterator :

 #include <iostream>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/iterator/counting_iterator.hpp>

template<class T>   
class ContainerTpl {
 public:
  typedef std::size_t Id;
  typedef boost::counting_iterator<Id> const_iterator;
  ContainerTpl() {}
  const_iterator begin() {
    return boost::counting_iterator<Id>(0);
  }
  const_iterator end() {
    return boost::counting_iterator<Id>(container_.size());
  }
 private:
  std::vector<T> container_;
};

int main () {
  typedef ContainerTpl<double> Container;
  Container c;
  BOOST_FOREACH (Container::Id cid, c) {
    std::cerr << cid << std::endl;
  }
  return 0;
}
  

Пожалуйста, обратите внимание, что это минимальный пример кода; в действительности класс содержит больше функциональности, так что, например, typedef to vector было бы недостаточно. Мне действительно нужен этот класс с итератором по идентификаторам.

К сожалению, приведенный выше код выдает мне довольно неприятные ошибки компилятора:

 In file included from boost/foreach.hpp:71,
                 from a.cpp:3:
boost/mpl/eval_if.hpp: In instantiation of ‘boost::mpl::eval_if<mpl_::bool_<false>, boost::range_const_iterator<ContainerTpl<double> >, boost::range_mutable_iterator<ContainerTpl<double> > >’:
boost/foreach.hpp:355:   instantiated from ‘boost::foreach_detail_::foreach_iterator<ContainerTpl<double>, mpl_::bool_<false> >’
a.cpp:25:   instantiated from here
boost/mpl/eval_if.hpp:38: error: no type named ‘type’ in ‘struct boost::range_mutable_iterator<ContainerTpl<double> >’
a.cpp: In function ‘int main()’:
a.cpp:25: error: no matching function for call to ‘begin(const boost::foreach_detail_::auto_any_baseamp;, boost::foreach_detail_::type2type<ContainerTpl<double>, mpl_::bool_<false> >*, boost::mpl::o
r_<boost::mpl::and_<boost::mpl::not_<boost::is_array<ContainerTpl<double> > >, mpl_::bool_<false>, mpl_::bool_<true>, mpl_::bool_<true>, mpl_::bool_<true> >, boost::mpl::and_<boost::mpl::not_<boo
st::foreach::is_noncopyable<ContainerTpl<double> > >, boost::foreach::is_lightweight_proxy<ContainerTpl<double> >, mpl_::bool_<true>, mpl_::bool_<true>, mpl_::bool_<true> >, mpl_::bool_<false>, m
pl_::bool_<false>, mpl_::bool_<false> >*)’
a.cpp:25: error: no matching function for call to ‘end(const boost::foreach_detail_::auto_any_baseamp;, boost::foreach_detail_::type2type<ContainerTpl<double>, mpl_::bool_<false> >*, boost::mpl::or_
<boost::mpl::and_<boost::mpl::not_<boost::is_array<ContainerTpl<double> > >, mpl_::bool_<false>, mpl_::bool_<true>, mpl_::bool_<true>, mpl_::bool_<true> >, boost::mpl::and_<boost::mpl::not_<boost
::foreach::is_noncopyable<ContainerTpl<double> > >, boost::foreach::is_lightweight_proxy<ContainerTpl<double> >, mpl_::bool_<true>, mpl_::bool_<true>, mpl_::bool_<true> >, mpl_::bool_<false>, mpl
_::bool_<false>, mpl_::bool_<false> >*)’
a.cpp:25: error: no matching function for call to ‘deref(const boost::foreach_detail_::auto_any_baseamp;, boost::foreach_detail_::type2type<ContainerTpl<double>, mpl_::bool_<false> >*) 

Как я могу заставить код работать?

ОБНОВЛЕНИЕ: После ответа я добавляю следующий код, который заставляет его работать:

 namespace boost
{
// specialize range_mutable_iterator and range_const_iterator in                                                                                                                                    
// namespace boost                                                                                                                                                                                  
template<class T>
struct range_mutable_iterator< ContainerTpl<T> > {
  typedef typename ContainerTpl<T>::const_iterator type;
};

template<class T>
struct range_const_iterator< ContainerTpl<T> > {
  typedef typename ContainerTpl<T>::const_iterator type;
};
} // end namespace         
  

Ответ №1:

В документах Boost есть страница об этом:

http://boost-sandbox.sourceforge.net/libs/foreach/doc/html/foreach/extensibility.html

Короче говоря, вам нужно определить boost::range_mutable_iterator<> для вашего типа, чтобы компилятор мог создать экземпляр типа шаблона, который BOOST_FOREACH пытается использовать.

редактировать для будущих пользователей Google:

Я не уверен, всегда ли этот URL-адрес «изолированной среды» будет указывать на последнюю версию или это временное местоположение, которое в конечном итоге сломается. Это ссылка на текущую версию, которая может быть более стабильной, хотя и устареет:

http://www.boost.org/doc/libs/1_50_0/doc/html/foreach/extensibility.html

Ответ №2:

Я знаю, что это старый вопрос, но все еще кажется актуальным. У меня была эта проблема, и я заметил, что для boost foreach требуется, чтобы у вас был изменяемый итератор, а также определенный const_iterator (таким образом, как ContainerTpl::iterator, так и ContainerTpl:: const_iterator). В противном случае вам нужно будет следовать инструкциям, предоставленным Tim.

Комментарии:

1. Это важно для того, чтобы это работало. В моем случае typedef iterator const_iterator было достаточно, но оно должно быть там. В противном случае вы получаете загадочные ошибки компилятора :/