2011-05-03 14 views
7

Tengo una clase que contiene algunos datos, y me gustaría agregar begin() y end() funciones que proporcionan iteradores sobre los ID de los datos.¿El iterador personalizado no funciona con BOOST_FOREACH?

estoy usando el 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; 
} 

Tenga en cuenta que se trata de código mínimo ejemplo; en realidad, la clase contiene más funcionalidades, por lo que, por ejemplo, un typedef a vector no sería suficiente. Realmente necesito esa clase, con un iterador sobre los ID.

Por desgracia, el código anterior me da errores de compilación bastante desagradables:

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_base&, 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_base&, 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_base&, boost::foreach_detail_::type2type<ContainerTpl<double>, mpl_::bool_<false> >*)’ 

¿Cómo puedo hacer que el código?

ACTUALIZACIÓN: A raíz de la respuesta, agrego el siguiente código, que hace que funcione:

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   

Respuesta

8

Hay una página en la documentación de Boost al respecto:

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

En pocas palabras necesita definir boost::range_mutable_iterator<> para su tipo para que el compilador pueda instanciar el tipo de plantilla que BOOST_FOREACH está tratando de usar.

de edición para los futuros empleados de Google:

no estoy seguro de si esa URL "caja de arena" siempre apuntará a la última versión o es una ubicación transitoria que eventualmente se romperá. Este es el enlace de la versión actual, que podría ser más estable, a pesar de que se convertirá en obsoleto:

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

2

Sé que esto es una cuestión de edad, pero todavía parece relevante. Tuve este problema y noté que boost foreach requiere que tenga un iterador mutable, así como un const_iterator definido (por lo tanto, tanto ContainerTpl :: iterator como ContainerTpl :: const_iterator). De lo contrario, necesitarás seguir las instrucciones provistas por Tim.

+0

Esto es esencial para que esto funcione. En mi caso, 'typedef iterator const_iterator' era suficiente, pero tiene que estar allí. De lo contrario, obtienes errores de compilador crípticos: / – Patryk

Cuestiones relacionadas