2009-01-20 17 views
12

¿Cómo puedo usar BOOST_FOREACH de manera eficiente (número de caracteres/facilidad de lectura) con un impulso :: ptr_map?Cómo usar BOOST_FOREACH con un impulso :: ptr_map?

Kristo demostró en su answer que es posible utilizar BOOST_FOREACH con un ptr_map, pero en realidad no me ahorra tener que escribir (o hace que mi código realmente más legible) de la iteración en la ptr_map con un iterador:

typedef boost::ptr_container_detail::ref_pair<int, int* const> IntPair; 
BOOST_FOREACH(IntPair p, mymap) { 
    int i = p.first; 
} 

// vs. 

boost::ptr_map<int, T>::iterator it; 
for (it = mymap.begin(); it != mymap.end(); ++it) { 
    // doSomething() 
} 

El siguiente código está en algún lugar de la línea que deseo. Sigue la forma estándar de cómo usar BOOST_FOREACH con un std :: map. Desafortunadamente esto no se compila:

boost::ptr_map<int, T> mymap; 
// insert something into mymap 
// ... 

typedef pair<int, T> IntTpair; 
BOOST_FOREACH (IntTpair &p, mymap) { 
    int i = p.first; 
} 

Respuesta

16

Como contenedores STL estilo, los contenedores tienen un puntero typedef value_type que puede utilizar:

#include <boost/ptr_container/ptr_map.hpp> 
#include <boost/foreach.hpp> 

int main() 
{ 
    typedef boost::ptr_map<int, int> int_map; 
    int_map mymap; 

    BOOST_FOREACH(int_map::value_type p, mymap) 
    { 
    } 
} 

encuentro que usar un typedef para el contenedor hace que el código sea mucho más fácil de escribir.

Además, debe intentar evitar el uso de los contenidos de los espacios de nombres detail en boost, es una convención de impulso que contengan detalles de implementación.

0

Debe compilar sin la referencia:

BOOST_FOREACH (IntTpair p, mymap) 

Creo que el problema es que los mapas en realidad no almacenar objetos como pares, sino como una estructura de árbol con la primera elemento como la clave, por lo que BOOST_FOREACH no puede obtener una referencia a un par, pero puede crear una copia temporal de uno.

1

Este ejemplo de código compilado para mí con g ++ 4.1.2:

#include "boost/ptr_container/ptr_map.hpp" 
#include "boost/foreach.hpp" 

int main() 
{ 
    boost::ptr_map<int, int> mymap; 

    typedef boost::ptr_container_detail::ref_pair<int, int* const> IntPair; 
    BOOST_FOREACH(IntPair p, mymap) 
    { 
     int i = p.first; 
    } 

    return 0; 
} 
+0

Gracias Kristo, esto es lo que finalmente también ocurrió. Sin embargo, para esto hay que escribir tanto en typedef, que no es una abreviación real sobre el estándar para (ptr_map :: iterator it = mymap.begin(); it! = Mymap.end(); ++ it) {} más ... – Martin

+0

Estoy de acuerdo. Estoy interesado en ver si hay una forma más corta (¿mejor?) Para escribir ese tipodef. También debes considerar a tus compañeros de trabajo. ¿Cuántos de ellos dirán: "Escribiste un tipo de letra loco solo para permitirte usar BOOST_FOREACH? Solo escribe un ciclo for-break normal y listo". :) –

8

Acabo de encontrarme con el mismo problema hoy. Desafortunadamente, la sugerencia de Daniel no funcionará con una referencia constante a un mapa. En mi caso, el ptr_map era miembro de una clase, y quería recorrerlo en una función de miembro constante. Tomando prestado el ejemplo de Daniel, esto es lo que tenía que hacer en mi caso:

#include "boost/ptr_container/ptr_map.hpp" 
#include "boost/foreach.hpp" 

int main() 
{ 
    typedef boost::ptr_map<int, int> int_map; 
    int_map mymap; 
    const int_map& mymap_const_ref(mymap); 

    BOOST_FOREACH(int_map::const_iterator::value_type p, mymap_const_ref) 
    { 
    } 
} 

Parece que int_map::const_iterator::value_type es equivalente a boost::ptr_container_detail::ref_pair<int, const int* const>.

0

using :: value_type no le permitirá const-iterate a través del contenedor. Uso los tipos de referencia del iterador

typedef boost::ptr_map< myKey, myPtrType > MyMap; 
MyMap m; 
BOOST_FOREACH(MyMap::iterator::reference it, m) 
    do_something(it.second); 
BOOST_FOREACH(MyMap::const_iterator::reference it, m) 
    do_something_const(it.second); 
0

Al final, decidí declarar la variable de iteración antes del ciclo.

std::pair<std::string, TrailStep*> step; 
BOOST_FOREACH(step, m_steps) 
{ 
    SAFE_DELETE(step.second); 
} 

Pero de hecho, debería haber una manera más simple. (¿Usar D en su lugar?)

1

que utilizan esta plantilla homebrew que añade un tipo de iteración que puede ser manejado por BOOST_FOREACH

namspace homebrew 
{ 
    template 
    < 
    class Key, 
    class T, 
    class Compare  = std::less<Key>, 
    class CloneAllocator = boost::heap_clone_allocator, 
    class Allocator  = std::allocator< std::pair<const Key,void*> > 
    > 
    class ptr_map : 
    public boost::ptr_map<Key,T,Compare,CloneAllocator,Allocator> 
    { 
    public: 
    typedef boost::ptr_container_detail::ref_pair<Key,const T* const> const_ref; 
    typedef boost::ptr_container_detail::ref_pair<Key,T* const> ref; 
    }; 
} 

Asumamos que foo y barra de son dos de sus tipos favoritos;)

typedef homebrew::ptr_map<foo,bar> Map; 
int f(const Map& m) 
{ 
    BOOST_FOREACH(Map::const_ref v, m) 
    { 
    v.first; // foo 
    v.second; // const bar* const 
    } 
} 

o

int f(Map& m) 
{ 
    BOOST_FOREACH(Map::ref v, m) 
    { 
    v.first; // foo 
    v.second; // bar* const 
    } 
} 

¡Lo que tienes que usar no parece depender de la forma en que lo usas en el ciclo (const o non-const) sino en la constness del mapa !! Por lo tanto, lo siguiente terminará en un error ...

int f(Map& m) 
{ 
    BOOST_FOREACH(Map::const_ref v, m) // can't use const_ref because m isn't const 
    { 
    ... 
    } 
} 

Weird! no es así?

Lo mejor para mí es que de todas las soluciones que se sugirieron aquí, esta es la primera que se maneja correctamente con la coloración de sintaxis Eclipse CDT (cuando se utiliza el atributo coloreado de sintaxis 'Código/Problema').

0

Usted puede tratar de esta manera súper-cool para iterar sobre mapas, ptr o de otra manera: https://svn.boost.org/trac/boost/attachment/ticket/3469/foreach_field.hpp

// no typedef needed 
BOOST_FOREACH_FIELD((int i)(const T& t), mymap) 
    // do something with i or t instead of first/second 

No estoy seguro de que funcionará con un parámetro de plantilla, pero tal vez utilizado sólo para que abstracción.

6

ahorrarse la mecanografía y mejorar la lectura mediante el uso de tuplas:

boost::ptr_map<int, T> mymap; 
int key; 
T * value; 
BOOST_FOREACH(boost::tie(key, value), mymap) 
{ 
    ... 
} 
+0

¿Alguna vez compiló? Pasando por el código histórico de '' tuple' y 'ptr_container', no puedo evitar concluir que no pudo (y cualquier intento de hacerlo falla). Ver [esta pregunta relacionada] (https://stackoverflow.com/questions/44588615/why-doesnt-boosttie-work-with-boost-foreach). –

Cuestiones relacionadas