Преобразование итераторов и const_iterators

Общий контекст:

Я пытаюсь создать контейнер, который будет вести себя как оболочка вокруг многомерного массива заданных во время выполнения измерений - фактически базовый массив, конечно, является одномерным массивом общего размера. Основная часть заключается в том, что operator [] возвращает обертку на вложенный массив.

Поскольку контейнерам нужны итераторы, в настоящее время я использую итераторы для этого контейнера. Container::iterator а также Container::const_iterator, Я стараюсь имитировать стандартные контейнерные итераторы, и они должны соблюдать все требования для произвольного доступа и выходных итераторов.

Я уже отметил следующие требования:

  • открытый конструктор по умолчанию
  • (конечно, семантика копирования и перемещения)
  • неявное преобразование из iterator к const_iterator
  • итератор и const_interator должны быть сопоставимы

Конкретный контекст:

Стандартные контейнеры-итераторы не обеспечивают никакого преобразования из const_iterator для iteratorпотому что удаление констант может быть опасным. Я уже искал SO для этой проблемы и нашел, как удалить constness const_iterator? где ответы предлагают разные приемы для удаления константности у оператора. Так что теперь я задаюсь вопросом, должен ли я реализовать явное преобразование из const_iterator в ala итератораconst_cast на указатели.

Вопрос:

Каковы риски в реализации явного преобразования из const_iterator в (не постоянный) iterator и чем он отличается от решений по связанному вопросу (скопировано здесь для удобства чтения):

  • используя аванс и расстояние (постоянное время от моих итераторов произвольного доступа)

    iter i(d.begin());
    advance (i,distance<ConstIter>(i,ci));
    
  • используя стирание:

    template <typename Container, typename ConstIterator>
    typename Container::iterator remove_constness(Container& c, ConstIterator it)
    {
        return c.erase(it, it);
    }
    

Для ссылок, вот упрощенная и частичная реализация моих итераторов:

// Base for both iterator and const_iterator to ease comparisons
template <class T>
class BaseIterator {
protected:
    T *elt;          // high simplification here...
    BaseIterator(T* elt): elt(elt) {}
    virtual ~BaseIterator() {}

public:
    bool operator == (const BaseIterator& other) {
        return elt == other.elt;
    }
    bool operator != (const BaseIterator& other) {
        return ! operator == (other);
    }
    // other comparisons omitted...

    BaseIterator& add(int n) {
        elt += n;
        return *this;
    }  
};

// Iterators<T> in non const iterator, Iterator<T, 1> is const_iterator
template <class T, int cnst=0, class U= typename std::conditional<cnst, const T, T>::type >
class Iterator: public BaseIterator<T> {
    using BaseIterator<T>::elt;

public:
    using value_type = U;
    using reference = U*;
    using pointer = U&;
    using difference_type = int;
    using iterator_category = std::random_access_iterator_tag;

    Iterator(): BaseIterator<T>(nullptr);
    Iterator(T* elt): BaseIterator<T>(elt) {}

    // conversion from iterator to const_iterator
    template <class X, typename = typename std::enable_if<
        (cnst == 1) && std::is_same<X, T>::value>::type>
    Iterator(const BaseIterator<X>& other): BaseIterator<X>(other) {};

    // HERE: explicit conversion from const_iterator to non const
    template <class X, typename = typename std::enable_if<
        std::is_same<X, T>::value && (cnst == 0)>::type>
    explicit Iterator(const Iterator<X, 1 - cnst>& other): BaseIterator<T>(other) {}

    // partial implementation below
    U& operator *() {
        return *elt;
    }
    U* operator ->() {
        return elt;
    }
    Iterator<T, cnst, U>& operator ++() {
        this->add(1);
        return *this;
    }
};

1 ответ

Решение

Оба указанных вами метода требуют неконстантного доступа к контейнеру, поэтому вы не можете получить доступ к базовым элементам const как неконстантным.

То, что вы предлагаете, не делает, так что это может быть UB [dcl.type.cv]

Другие вопросы по тегам