2010-06-28 12 views
10

Obecnie próbuję wydrukować historię ruchów dla graczy w grze, nad którą pracuję. Pod koniec każdej rundy każdy gracz przesunął pewną ilość w kierunku dodatnim lub ujemnym, a to zostało zarejestrowane jako int w wektorze ruchu. W końcu chcę wytyczyć kierunki przesunięte w funkcji czasu dla każdego odtwarzacza, ale mam problem z wyodrębnieniem danych z wektora 2d.Powtarzanie dwuwymiarowego wektora STL C++

Więc pierwszą rzeczą, którą starałem się po prostu iteracyjne i wydrukować wszystkie elementy, jednak to nie skompilować:

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; 
     } 
    } 

} 

Kompilator daje ten komunikat o błędzie, który ja naprawdę nie rozumiem:

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> > > > >&) 

Każda pomoc jest bardzo doceniana!

Odpowiedz

14

Musisz użyć const_iterator jeśli vector jest const odniesienia. Ponadto, aby wyprowadzić col, wystarczy wyłuskać je tylko raz.

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; 
     } 
    } 
} 

EDIT: przy użyciu typedefs uczyni Twój kod bardziej czytelnym

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

Chciałbym twierdzić, że jeśli masz zamiar napisać ponownie e-kod, warto byłoby również poprawnie umieścić deklaracje 'row' i' col' w pętli 'for' dla odpowiedniego zakresu. –

+0

Również może być nieco więcej C++ - jak gdyby 'output_movement' był nazywany' operator << '. – Philipp

+0

@Matthieu Zaktualizowałem swoją odpowiedź, aby uwzględnić Twoją sugestię. –

4

const powrót obiektów const_iterators, więc po prostu zamień iterator przez const_iterator wszędzie. Zapobiega to również niepożądanym modyfikacjom wektorów.

Jest to kombinacja Sam i sugestie 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

2D vector deklaruje const, więc trzeba użyć const_iterator zamiast iterator.

Nie należy również podwójnie dereferencji col. Jest to iterator, więc wystarczy raz wyrejestrować.

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, coś jest lepszy niż ten bałagan for pętli. Oto kilka alternatyw. Wybierz, który chcesz.

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)); 
} 

lub

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; }); 
       }); 
} 

albo moje osobiste preferencje (zwiększanie/foreach.hpp)

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

John, zasugerował użycie lambdy, ale jeśli C++ 11 dostępne, wolałabym

+0

+1 dla czystych pętli opartych na zasięgu - chociaż nie ma potrzeby, aby "&" było? –

+0

Christian: Tak, jest! W przeciwnym razie każdy wiersz zostanie skopiowany i powtórzony. Drugie odniesienie nie jest tak istotne. – Petter

+0

Ben: Och, to: tak, oczywiście. Ale możesz równie dobrze napisać 'const auto &', aby upewnić się, że przypadkowo nie zmienisz 'row's lub' elem'ents, nie? –