简体   繁体   中英

C++ how to build iterator for vector of vectors

I have a two-dimensional array which I have implemented as a std::vector of std::vector s, like so:

struct Cell
{};

struct Column
{ std::vector<Cell*> m_column; };

struct Grid
{ std::vector<Column> m_grid; }

I want to build an input iterator class for Grid, so that you can do this...

for (const auto cell : grid)
    cell->doSomething();

...and use other STL algorithms. But I'm not sure how to make the iterator increment function.

Here's what I have so far:

struct Grid
{
    std::vector<Column> m_grid;

    struct ConstIterator
    {
        using value_type = const Cell*;
        using reference = const Cell*&;
        using pointer = const Cell**;
        using difference_type = std::ptrdiff_t;
        using iterator_category = std::input_iterator_tag;

        reference operator* () { return curr; }

        ConstIterator& operator++ () { incrementAcrossGrid(); return *this; }
        ConstIterator operator++(int) { const auto temp(*this); incrementAcrossGrid(); return temp; }

        bool operator== (const ConstIterator& that) { return curr == that.curr; }
        bool operator!= (const ConstIterator& that) { return !(*this == that); }

        void incrementAcrossGrid()
        {
            // ???
        }

        const Cell* curr;
    };

    ConstIterator begin() const { return { m_grid.front().m_column.front() }; }
    ConstIterator end() const { return { m_grid.back().m_column.back() + 1 }; } // Is there a better way to get the end?
};

As you can see, I'm not sure what to put inside incrementIterator() . It's easy to increment it until it reaches the end of its column, but I don't know how to point it from the bottom of one column to the top of the next.

It might be that I'm taking entirely the wrong approach, so all suggestions are welcome (including Boost libraries, etc.). The important thing is that I need to be able to use Grid::begin() and Grid::end() to iterate over the Cells.

The basic idea is to keep two iterators inside your custom one:

struct Iterator {
    reference operator* () { 
        return *cell_iterator;
    }

    Iterator& operator++() {
        if (++cell_iterator == col_iterator->m_column.end()) {
            ++col_iterator;
            cell_iterator = col_iterator->m_column.begin();
        }
        return *this;
    }

    bool operator==(const Iterator& that) const {
        return col_iterator == that.col_iterator && 
               cell_iterator == that.cell_iterator;
    }
    
    std::vector<Cell*>::iterator  cell_iterator;
    std::vector<Column>::iterator col_iterator;
};

auto Grid::begin() -> Iterator {
    return Iterator{m_grid.begin()->m_column.begin(), m_grid.begin()};
}

This is only an idea. You should think about how to represent Grid::end() iterator correctly and make necessary changes to operator++() . When col_iterator hits m_grid.end() , you can no longer dereference it to get next cell_iterator .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM