【问题标题】:Iterating over 2-dimensional STL vector c++迭代二维 STL 向量 c++
【发布时间】:2010-06-28 11:39:33
【问题描述】:

我目前正在尝试打印我正在开发的游戏中玩家的运动历史。在每一轮结束时,每个玩家都在正或负方向移动了一些量,这被记录为移动向量中的 int。最终,我想绘制每个玩家的移动方向与时间的关系,但我无法从二维向量中提取数据。

所以我尝试的第一件事就是迭代并打印所有元素,但这并不能编译:

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

非常感谢任何帮助!

【问题讨论】:

    标签: c++ stl vector


    【解决方案1】:

    如果vector 是常量引用,则需要使用const_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;
             }
        }
    }
    

    编辑:使用 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;
        }
    }
    

    【讨论】:

    • 我认为,如果您要重写代码,也值得将 rowcol 声明正确地放入 for 循环中以进行适当的范围界定。跨度>
    • 另外,如果 output_movement 被称为 operator&lt;&lt;,它可能会更像 C++。
    • @Philipp:我不确定。重载运算符总是很棘手,尤其是当可能有多个显示时。
    【解决方案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 对象返回const_iterators,因此只需将iterator 替换为const_iterator。这也可以防止对向量进行不必要的修改。

      这是 Sam 和 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;
      }
      

      【讨论】:

        【解决方案4】:

        John,你建议使用 lambda,但如果 C++11 可用,我更喜欢

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

        【讨论】:

        • +1 用于干净的基于范围的循环——虽然不需要'&',是吗?
        • 克里斯蒂安:是的,有!否则,每一行都将被复制和迭代。第二个参考并不那么重要。
        • 本:哦,那个:是的,当然。但是,您不妨写const auto &amp; 以确保您不会意外更改您的rows 或elements,不是吗?
        【解决方案5】:

        Omg,anything 比那些乱七八糟的 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;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-12-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-05
          • 2016-10-11
          • 2020-11-06
          • 2021-09-03
          相关资源
          最近更新 更多