代码之家  ›  专栏  ›  技术社区  ›  Serge Ballesta

转换迭代器和常量迭代器

  •  1
  • Serge Ballesta  · 技术社区  · 6 年前

    一般情况:

    我试图构建一个容器,它将作为运行时定义维度的多维数组的包装器-事实上,底层数组当然是总大小的1D数组。主要部分是 operator [] 返回子数组的包装。

    由于容器需要迭代器,我目前正在该容器上实现迭代器,两者 Container::iterator Container::const_iterator . 我努力模仿标准容器迭代器,它们应该尊重随机访问和输出迭代器的所有要求。

    我已经注意到以下要求:

    • 公共默认构造函数
    • (当然是复制和移动语义)
    • 隐式转换 iterator 到A const_iterator
    • 迭代器和const_interator应该是可比较的

    特定上下文:

    标准容器迭代器根本不提供 常量迭代器 迭代器 ,因为移除constness可能很危险。我已经找过这个问题了 How to remove constness of const_iterator? 其中,答案提出了不同的技巧,以从运算符中移除常量。所以我现在想知道我是否应该实现 明确的 从const_迭代器到迭代器的转换 阿拉尔 const_cast 关于指针。

    问题:

    在实现从 常量迭代器 致A(非常量) 迭代器 与链接问题的解决方案有何区别(复制此处以便于阅读):

    • 使用advance和distance(来自随机访问迭代器的常数时间)

      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 回复  |  直到 6 年前
        1
  •  1
  •   Caleth    6 年前

    您引用的两个方法都需要对容器的非const访问,因此您无法以非const的身份访问const底层元素。

    你的建议没有,所以可能是ub [dcl.type.cv]