Итерация над двумерным вектором STL С++

В настоящее время я пытаюсь распечатать историю движений игроков в игре, над которой я работаю. В конце каждого раунда каждый игрок перемещал некоторое количество в положительном или отрицательном направлении, и это регистрируется как int в векторе движения. В конце концов, я хочу, чтобы нарисовать направление, перемещенное против времени для каждого игрока, но у меня возникли проблемы с извлечением данных из 2-го вектора.

Итак, первое, что я пробовал, - просто перебрать и распечатать все элементы, однако это не скомпилируется:

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

}

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

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

Любая помощь очень ценится!

Ответ 1

Вам нужно использовать const_iterator, если vector является ссылкой на константу. Кроме того, для вывода col вам нужно только разыменовать его один раз.

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

Изменить: использование typedefs сделает ваш код более удобочитаемым

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

Ответ 2

2D vector объявлен const, поэтому вам нужно использовать const_iterator вместо iterator.

Вы также не должны дважды разыгрывать col. Это итератор, поэтому вам нужно только разыменовать один раз.

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

} 

Ответ 3

const object return const_iterators, поэтому просто замените iterator на const_iterator всюду. Это также предотвращает нежелательные изменения векторов.

Это комбинация предложений Сэма и Матье:

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

Ответ 4

Джон, вы предложили использовать lambdas, но если С++ 11 доступен, я бы предпочел

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

Ответ 5

Omg, все лучше, чем этот беспорядок в циклах for. Вот несколько альтернатив. Выберите то, что вам нравится.

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

или,

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

или, мои личные предпочтения (boost/foreach.hpp),

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