简体   繁体   中英

Custom iterator function for c++

I have a collection of object of type "T" that i want to iterate through. An object of type "T" has two important properties:

int r; // row number
int c; // column number 

I would like to define an iterator that allows me to iterate through all elements of the collection.

This can be done using:

std::vector<T> v;

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    ....
}

However, I would like the iterator to have one more property. I would like to be able to call

it.nextrow()

calling this function should return the element "e" of v where er + 1 = ec.r and ec = ec.c, where ec is the current element pointed by the iterator. Ie calling it.nextrow() should give me a pointer to the element where column is the same, but row is incremented by one. Hope it makes sense.

I am not sure what I need to do in order for this to work, as I am fairly new to advanced c++ concepts. Can anybody help me?

Not everything has to be a member function. Would you accept a iterator nextRow(iterator current, iterator begin, iterator end) free function?

template<typename Iterator>
Iterator nextRow(Iterator needle, Iterator begin, Iterator end)
{
    return std::find_if(begin, end, [needle](const T & elem) { return (elem.r == needle->r + 1) && (elem.c == needle->c); });
}

If your vector is always sorted, you don't need a separate begin, just use needle.

If you do need this to be a part of a wrapper iterator, that type will need to contain a begin and end.

template <typename Iterator>
class SearchableIterator
{
    Iterator wrapped, begin, end;
public:
    difference_type     Iterator::difference_type;
    value_type          Iterator::value_type;
    pointer             Iterator::pointer;
    reference           Iterator::reference
    iterator_category   Iterator::iterator_category

    SearchableIterator(Iterator wrapped, Iterator begin, Iterator end)
      : wrapped(wrapped), begin(begin), end(end) {}

    // All the members, calling that member of wrapped (see std::reverse_iterator for guidance)

    SearchableIterator nextRow()
    {
        return SearchableIterator(std::find_if(begin, end, [this](const T & elem) { return (elem.r == wrapped->r + 1) && (elem.c == wrapped->c); }), begin, end);
    }
}

Iterators are copyable.

You can

  • derive from the container's iterator for your container,
  • add construction from the container's iterator,
  • add your extra property members,
  • and declare that begin(), end(), etc from your custom container return your derived iterator.

Assuming your data are packed in a vector with consecutive items for all columns of a row followed by items of the next row, you would just need *(iterator + column_count) to access the next-row-same-column value (don't try this on an iterator that's already pointing into the last row of data)

You can create a wrapper iterator similar to Implement custom iterator for c++ std container and give it a specific column count as additional information:

template<typename T, int colsize, typename TIterator = std::vector<T>::iterator>
class MyRowIterator : public std::iterator<std::forward_iterator_tag, T>
{
private:
    TIterator m_pter;
public:

    MyRowIterator(TIterator& value):  m_pter(value)
    {
    }
    MyRowIterator(const MyRowIterator& other_it): m_pter(other_it.m_pter)
    {
    }
    MyRowIterator& operator++()
    {
        ++m_pter;
        return *this;
    }
    bool operator!=(const MyRowIterator& rhs)
    {
        return m_pter != rhs.m_pter;
    }
    T& operator*()
    {
        return (*m_pter);
    }
    // here it is
    T& nextrow()
    {
        return *(m_pter+colsize);
    }
};

Usage example:

void Test()
{
    std::vector<int> data;

    // 2 rows each 10 columns
    data.resize(20);
    for (auto& item : data)
    {
        item = 0;
    }
    data[2] = 1;
    data[12] = 5;

    // don't iterate the last line, else nextrow() will access out of bounds!
    for (MyRowIterator<int, 10> iter = data.begin(); iter != (data.end()-10); iter++)
    {
        std::cout << *iter << " # " << iter.nextrow() << std::endl;
    }
}

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