Подскажите, люди знающие, как грамотно сделать итератор для vector<vector<T> > так, чтобы внешняя семантика оставалась, как у итератора одного контейнера? Нужно обойти все элементы по одному разу. Типы контейнеров могут быть другими, это не принципиально, например vector<list<T> > или list<list<T> >.
Я пробовал делать по-разному, но всё время возникает одна и та же проблема: непонятно, как сравнивать итераторы в конце — что считать за общий end(). Если внешний it1_ упирается в свой end(), то значение внутреннего it2_ оказывается неопределённым. Поэтому появляются трудности с реализацией функции operator==():
template <class T>
class MyContainer
{
typedef std::vector<T> Inner;
typedef std::vector<Inner> Outer;
Outer contents_;
public:
class iterator
{
friend class MyContainer;
Outer::iterator it1_;
Inner::iterator it2_, it2end_;
bool isEnd_; // <<<<< костыль
iterator(Outer::iterator it1, bool) : it1_(it1), isEnd(false) {
it2_ = it1_->begin();
it2end_ = it1_->end();
}
iterator(Outer::iterator it1) : it1_(it1), isEnd(true) {}
public:
T& operator*() { return *it2_; }
iterator& operator++() {
if(++it2_==it2end_) {
++it1_;
it2_ = it1_->begin();
it2end_ = it1_->end();
}
}
bool operator==(iterator it) const {
return it1_==it.it1_ &&
(isEnd_==it.isEnd_ || it2_==it.it2_);
}
};
iterator begin() { return iterator(contents_.begin(), true); }
iterator end() { return iterator(contents_.end()); }
};
В этом коде используется костыль в виде дополнительной переменной isEnd_, которая устанавливается в true для конца первого контейнера (когда значения it2_ и it2end_ не определены). Это увеличивает размер данных под итератор и количество операций сравнения в шаге цикла for(;it!=itEnd; ). Можно ли данную задачу решить изящнее, без дополнительной переменной и дополнительного сравнения?