2010-06-28 27 views
10

Actualmente estoy tratando de imprimir un historial de movimientos para jugadores en un juego en el que estoy trabajando. Al final de cada ronda, cada jugador ha movido una cierta cantidad en la dirección positiva o negativa y esto se registra como un int en el vector de movimiento. Finalmente, quiero trazar las direcciones movidas frente al tiempo para cada jugador, pero estoy teniendo problemas para extraer los datos del vector 2d.Iteración sobre el vector bidimensional STL C++

Así que lo primero que intenté fue simplemente recorrer e imprimir todos los elementos, sin embargo esto no se compila:

void output_movement(const std::vector< std::vector<int> > & movement){ 

    std::vector< std::vector<int> >::iterator row; 
    std::vector<int>::iterator col; 
    for (row = movement.begin(); row != movement.end(); ++row) { 
     for (col = row->begin(); col != row->end(); ++col) { 
      std::cout << **col; 
     } 
    } 

} 

El compilador da este mensaje de error que yo no entiendo muy bien:

hg_competition.cpp:45: error: no match for ‘operator=’ in ‘row = ((const std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >*)money_movement)->std::vector<_Tp, _Alloc>::begin [with _Tp = std::vector<int, std::allocator<int> >, _Alloc = std::allocator<std::vector<int, std::allocator<int> > >]()’ 
/usr/include/c++/4.4/bits/stl_iterator.h:669: note: candidates are: __gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> >*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >& __gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> >*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >::operator=(const __gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> >*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >&) 

¡Toda ayuda es muy apreciada!

Respuesta

14

Es necesario utilizar un const_iterator si el vector es una referencia constante. Además, para dar salida a col, solo necesita desreferenciarlo una vez.

void output_movement(const std::vector< std::vector<int> > & movement){ 

    std::vector< std::vector<int> >::const_iterator row; 
    std::vector<int>::const_iterator col; 
    for (row = movement.begin(); row != movement.end(); ++row) { 
     for (col = row->begin(); col != row->end(); ++col) { 
      std::cout << *col; 
     } 
    } 
} 

Editar: usando typedefs hará que su código sea más legible

typedef std::vector<int> Vector; 
typedef std::vector<Vector> DoubleVector; 

void output_movement(
    const DoubleVector& movement 
) 
{ 
    for (DoubleVector::const_iterator row = movement.begin(); row != movement.end(); ++row) { 
     for (Vector::const_iterator col = row->begin(); col != row->end(); ++col) { 
      std::cout << *col; 
     } 
     std::cout << std::endl; 
    } 
} 
+1

yo diría que si vas a reescribir º El código e, podría valer la pena también poner apropiadamente las declaraciones 'row' y' col' dentro del ciclo 'for' para el alcance apropiado. –

+0

También podría ser un poco más C++ - como si 'output_movement' se llamara' operator << '. – Philipp

+0

@Matthieu He actualizado mi respuesta para incluir su sugerencia. –

4

const objetos regresan const_iterators, por lo que simplemente reemplazar iterator por const_iterator todas partes. Esto también evita modificaciones no deseadas de los vectores.

Ésta es la combinación de Sam y de las sugerencias de Mathieu:

#include <ostream> 
#include <vector> 

typedef std::vector<int> Vector; 
typedef std::vector<Vector> DoubleVector; 


template<typename Char, typename Traits> 
std::basic_ostream<Char, Traits>& 
operator<<(std::basic_ostream<Char, Traits>& stream, 
      const DoubleVector& movement) { 
    for (DoubleVector::const_iterator row = movement.begin(); row != movement.end(); ++row) { 
     for (Vector::const_iterator col = row->begin(); col != row->end(); ++col) { 
      stream << *col; 
     } 
    } 
return stream; 
} 
12

El 2D vector se declara const, por lo que es necesario utilizar const_iterator en lugar de iterator.

Tampoco debe desviarse doblemente col. Es un iterador, por lo que solo necesita desreferencia una vez.

void output_movement(const std::vector< std::vector<int> > & movement){ 

    std::vector< std::vector<int> >::const_iterator row; 
    std::vector<int>::const_iterator col; 
    for (row = movement.begin(); row != movement.end(); ++row) { 
     for (col = row->begin(); col != row->end(); ++col) { 
      std::cout << *col; 
     } 
    } 

} 
0

Omg, nada es mejor que el lío de for bucles. Aquí algunas alternativas. Elige cualquiera que te guste.

typedef vector<int> VI; 
typedef vector<VI> VVI; 


namespace std { 
    ostream& operator<<(ostream& o, const VI& v) { 
     copy (v.begin(), v.end(), ostream_iterator<int>(cout)); 
     return o; 
    } 
} 
void output_movement (const VVI& m) { 
    copy (m.begin(), m.end(), ostream_iterator<const VI&>(cout)); 
} 

o,

void output_movement (const VVI & m) { 
    for_each (m.begin(), m.end(), [](const VI& v){ 
       for_each (v.begin(), v.end(), [](int i){ cout << i; }); 
       }); 
} 

o, mi preferencia personal (impulso/foreach.hpp),

void output_movement (const VVI & m) { 
    foreach (const VI& v, m) 
     foreach (int i, v) 
      cout << i; 
} 
3

Juan, se sugirió el uso de lambdas, pero si es C++ 11 disponibles, preferiría

for (auto& row : movement) { 
    for (auto& elem : row) { 
     std::cout << elem; 
    } 
} 
+0

+1 para los bucles limpios basados ​​en el rango - aunque no es necesario el '&', ¿verdad? –

+0

Christian: ¡Sí, hay! De lo contrario, cada fila se copiará y repetirá. La segunda referencia no es tan crucial. – Petter

+0

Ben: Oh, eso: sí, ciertamente. Pero entonces también podrías escribir 'const auto &' para asegurarte de que no cambias accidentalmente tus 'row's o' elem'ents, ¿no? –

Cuestiones relacionadas