итерация инкапсулированных вложенных контейнеров STL - PullRequest
6 голосов
/ 12 июля 2011

Вот довольно обычная инкапсуляция контейнера STL, которая позволяет пользователю Cfoo выполнять итерацию контейнера, не допуская изменений во внутренностях.

#include <vector>

class Cfoo
{
public:
    class Cbar
    {
        /* contents of Cbar */
    };
    typedef std::vector<Cbar> TbarVector;
    typedef TbarVector::const_iterator const_iterator;     
public:
    const_iterator begin() const { return( barVector_.begin() ); }
    const_iterator end() const { return( barVector_.end() ); }
private:
    TbarVector barVector_;
};

Пока все хорошо.Мы можем перебрать контейнер так:

Cfoo myFoo;
for (Cfoo::const_iterator it = myFoo.begin(); it != myFoo.end(); ++it)
{
   it->DoSomething();
}

Теперь я хочу заменить std :: vector на вложенный std :: vector:

public:
    typedef std::vector<Cbar> TbarVectorInner;
    typedef std::vector<TbarVectorInner> TbarVectorOuter;

private:
    TbarVectorOuter barContainer_;

Но я хочу бытьвозможность перебирать все экземпляры Cbar таким же образом, как и раньше, предоставляя const_iterator, методы begin () const и end () const.

Мне не ясно, как это сделать, хотя я подозреваю, что это требует написания собственного итератора.Есть мысли?

1 Ответ

4 голосов
/ 12 июля 2011

Ни один из стандартных итераторов не может выполнять итерацию более чем в одном контейнере, поэтому ваше предположение верно - вам придется написать собственный итератор.

Это можно сделать в общеммода, если у вас есть промежуточный итератор, который возвращает пары итераторов (начало, конец) во внутренние контейнеры.

Некоторый непроверенный код для начала:

template<typename T, typename OuterIterator, typename InnerIterator>
class Iterator2d : std::Iterator
{
public:
    Iterator2d(OuterIterator begin, OuterIterator end) : m_begin(begin), m_end(end), m_currentOuter(begin)    {
        if (m_currentOuter != m_end)
             m_currentInner = m_begin->first;
        Normalize();
    }
    Iterator2d & operator++()
    {
        if (m_currentOuter != m_end)
        {
            ++m_currentInner;
            Normalize();
        }
        return *this;
    }
    T & operator*()
    {
        return *m_currentInner;
    }
private:
    void Normalize()
    {
        while (m_currentOuter != m_end && m_currentInner == m_currentOuter->second)
        {
            ++m_currentOuter;
            if (m_currentOuter != m_end)
                m_currentInner = m_currentOuter->first;
        }
    }

    OuterIterator m_begin;
    OuterIterator m_end;
    OuterIterator m_currentOuter;
    InnerIterator m_currentInner;
};

Это только началоЯ могу вернуться, чтобы закончить это - или нет, в зависимости от эта реализация уже охватывает то же самое основание.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...