Информация об изменениях

Сообщение Re: про итераторы от 27.03.2020 13:26

Изменено 27.03.2020 13:38 rg45

Re: про итераторы
Здравствуйте, qaz77, Вы писали:

Q>Делаю STL-совместимый самодельный контейнер, который обертка над стандартными контейнерами.

Q>Соответственно, потребовались iterator и const_iterator.
Q>Вопрос про то, как лучше/удобнее реализовать эту парочку, с минимумом копипасты и односторонней заменяемости от iterator к const_iterator.
Q>Что-то я не нашел гайдлайнов для такой задачи...

Я вот здесь набросал простейший proof-of-concept контейнера-враппера для std::vector и враппера для итераторов с использованием boost::iterator_adaptor. Как видишь, все, что потребовалось — это один единственный дополнительный конструктор. Даже операторы сравнения и вычитания не пришлось определять самому:

http://coliru.stacked-crooked.com/a/bfbaf2d3bd65bbd2

#include <iostream>
#include <vector>
#include <boost/iterator/iterator_adaptor.hpp>

template <typename BaseIteratorT>
class MyIteratorBase
 : public boost::iterator_adaptor<MyIteratorBase<BaseIteratorT>, BaseIteratorT>
{
    using iterator_adaptor = boost::iterator_adaptor<MyIteratorBase<BaseIteratorT>, BaseIteratorT>;

 public:

    using iterator_adaptor::iterator_adaptor;

    MyIteratorBase() = default;

    template <typename U>
    MyIteratorBase(const MyIteratorBase<U>& rhs) : iterator_adaptor(rhs.base()) {}

};

template <typename T>
class MyVector
{
public:

    using iterator = MyIteratorBase<typename std::vector<T>::iterator>;
    using const_iterator = MyIteratorBase<typename std::vector<T>::const_iterator>;

    MyVector() = default;
    MyVector(std::initializer_list<T> l) : m_v{l} {}

    iterator begin() { return iterator(m_v.begin()); }
    iterator end() { return iterator(m_v.end()); }

    const_iterator begin() const { return const_iterator(m_v.begin()); }
    const_iterator end() const { return const_iterator(m_v.end()); }

private:
    std::vector<T> m_v;
};

int main() {

    MyVector<int> my_v {0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    for (const auto& e : my_v)
    {
        std::cout << " " << e;
    }
    std::cout << std::endl;


    MyVector<int>::iterator begin = my_v.begin();
    MyVector<int>::const_iterator end = my_v.end();

    std::cout << std::boolalpha;
    std::cout << (begin == end) << std::endl; // false
    std::cout << (begin != end) << std::endl; // true
    std::cout << (begin <= end) << std::endl; // true
    std::cout << (end - begin) << std::endl; // 10

}
Re: про итераторы
Здравствуйте, qaz77, Вы писали:

Q>Делаю STL-совместимый самодельный контейнер, который обертка над стандартными контейнерами.

Q>Соответственно, потребовались iterator и const_iterator.
Q>Вопрос про то, как лучше/удобнее реализовать эту парочку, с минимумом копипасты и односторонней заменяемости от iterator к const_iterator.
Q>Что-то я не нашел гайдлайнов для такой задачи...

Я вот здесь набросал простейший proof-of-concept контейнера-враппера для std::vector и враппера для итераторов с использованием boost::iterator_adaptor. Как видишь, все, что потребовалось — это один единственный дополнительный конструктор. Даже операторы сравнения и вычитания не пришлось определять самому:

http://coliru.stacked-crooked.com/a/dcd22f47ba5d7da7

#include <iostream>
#include <vector>
#include <boost/iterator/iterator_adaptor.hpp>

template <typename BaseIteratorT>
class MyIterator
 : public boost::iterator_adaptor<MyIterator<BaseIteratorT>, BaseIteratorT>
{
    using iterator_adaptor = boost::iterator_adaptor<MyIterator<BaseIteratorT>, BaseIteratorT>;

 public:

    using iterator_adaptor::iterator_adaptor;

    MyIterator() = default;

    template <typename U>
    MyIterator(const MyIterator<U>& rhs) : iterator_adaptor(rhs.base()) {}

};

template <typename T>
class MyVector
{
public:

    using iterator = MyIterator<typename std::vector<T>::iterator>;
    using const_iterator = MyIterator<typename std::vector<T>::const_iterator>;

    MyVector() = default;
    MyVector(std::initializer_list<T> l) : m_v{l} {}

    iterator begin() { return iterator(m_v.begin()); }
    iterator end() { return iterator(m_v.end()); }

    const_iterator begin() const { return const_iterator(m_v.begin()); }
    const_iterator end() const { return const_iterator(m_v.end()); }

private:
    std::vector<T> m_v;
};

int main() {

    MyVector<int> my_v {0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    for (const auto& e : my_v)
    {
        std::cout << " " << e;
    }
    std::cout << std::endl;


    MyVector<int>::iterator begin = my_v.begin();
    MyVector<int>::const_iterator end = my_v.end();

    std::cout << std::boolalpha;
    std::cout << (begin == end) << std::endl; // false
    std::cout << (begin != end) << std::endl; // true
    std::cout << (begin <= end) << std::endl; // true
    std::cout << (end - begin) << std::endl; // 10

}