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
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.