iterator, const_iterator, шаблоны
От: Baskak Россия  
Дата: 28.11.17 14:08
Оценка:
Добрый день.
Пишу свой контейнер (в образовательных целях), возникла непонятная ситуация с итераторами. Нужно реализовать iterator и const_iterator.
Оба наследуются от std::iterator (вернее оба наследуются от шаблона (в котором общий для итераторов код), который наследуется от std::iterator).
Ниже приведен упрощенный пример, он полностью рабочий (за исключением того, что вместо iterator написано norm_iterator).
Строки, помеченные (1) и (2) нужны для того чтобы можно было сравнивать iterator и const_iterator между собой.
Из-за этого пришлось добавить строчку (3), и возникла ошибка при компиляции (она возникает если заменить norm_iterator на iterator в коде):

error C2039: 'pt': is not a member of 'std::iterator<std::input_iterator_tag,T,ptrdiff_t,_Ty *,_Ty &>'


iterator_base является наследником std::iterator, а norm_iterator в свою очередь наследник iterator_base.
Ошибка в том, что операторы в строках (1) и (2), видя тип параметра (const iterator&), думают что им передают std::iterator, у которого нет члена pt, который есть у iterator.

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

Как правильно реализовать итераторы?
Чтобы воспроизвести ошибку, в коде нужно заменить norm_iterator на iterator.
Компилятор Visual C++ 2015.

  код
// iterator + const_iterator
#include <iterator>
#include <iostream>
#include <conio.h>

template<class T> class C
{
    T t[5];

public:

    template <class X> class iterator_base : public std::iterator<std::input_iterator_tag, T>
    {
        X pt;
        friend class C<T>;

    protected:
        iterator_base()
        {
            pt = nullptr;
        }

    public:
        bool operator==(const iterator_base& it)
        {
            return pt == it.pt;
        }

        bool operator!=(const iterator_base& it)
        {
            return !operator==(it);
        }

        iterator_base& operator++()
        {
            pt++;
            return *this;
        }

        iterator_base& operator++(int)
        {
            auto tmp = *this;
            operator++();
            return tmp;
        }

        const T& operator*() const
        {
            return *pt;
        }

    };

    typedef typename T* PT;
    typedef typename const T* CPT ;

    class const_iterator; // (3) чтобы можно было написать (1) и (2)

    class norm_iterator : public iterator_base<PT>
    {
        friend class C<T>;
    public:
        norm_iterator() : iterator_base<PT>()
        {
        }

        norm_iterator(const PT& p)
        {
            pt = p;
        }

        norm_iterator(const norm_iterator& it)
        {
            pt = it.pt;
        }

        bool operator==(const norm_iterator& it)
        {
            return pt == it.pt;
        }

        bool operator!=(const norm_iterator& it)
        {
            return !operator==(it);
        }

        bool operator==(const const_iterator& it)
        {
            return pt == it.pt;
        }

        bool operator!=(const const_iterator& it)
        {
            return !operator==(it);
        }

        T& operator*()
        {
            return *pt;
        }

    };

    class const_iterator : public iterator_base<CPT>
    {
        friend class C<T>;
    public:
        const_iterator() : iterator_base<CPT>()
        {
        }

        const_iterator(const CPT& p)
        {
            pt = p;
        }

        const_iterator(const const_iterator& it)
        {
            pt = it.pt;
        }

        const_iterator(const norm_iterator& it)
        {
            pt = it.pt;
        }

        bool operator==(const const_iterator& it)
        {
            return pt == it.pt;
        }

        bool operator!=(const const_iterator& it)
        {
            return !operator==(it);
        }

        bool operator==(const norm_iterator& it) // (1)
        {
            return pt == it.pt;
        }

        bool operator!=(const norm_iterator& it) // (2)
        {
            return !operator==(it);
        }
    };

    C()
    {
    }

    norm_iterator begin()
    {
        return norm_iterator(&t[0]);
    }

    const_iterator begin() const
    {
        return (const_iterator(&t[0]));
    }

    norm_iterator end()
    {
        return (norm_iterator(&t[5]));
    }

    const_iterator end() const
    {
        const_iterator it;
        it.pt = &t[5];
        return it;
    }
    
};


int main()
{
    C<int> c;
    int i = 0;
    for (auto it = c.begin(); it != c.end(); it++, i++)
        *it = i + 1;

    const auto& cc = c;
    C<int>::const_iterator it = c.begin();

    for (auto x : cc)
        std::cout << x << ' ';
    
    // убедимся что можно бы сравнивать с константным итератором и наоборот
    bool b00 = (c.end() == cc.end());
    bool b01 = (c.end() != cc.end());
    bool b10 = (cc.end() == c.end());
    bool b11 = (cc.end() != c.end());
    bool b20 = (cc.end() == cc.end());
    bool b21 = (cc.end() != cc.end());
    bool b30 = (c.end() == c.end());
    bool b31 = (c.end() != c.end());

    _getch();
}
iterator, const_iterator, шаблоны
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.