微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从迭代器构造const_iterator

如何解决从迭代器构造const_iterator

我正在为一些自定义容器实现一个简单的迭代器(基于列表):

template <class T,class Link>
class single_iterator
{
public:

    using iterator_category = std::forward_iterator_tag;

    //A value is not T but T*,because the list is a contaner of elements of type T *.
    using value_type = T *;

    //required by std::iterator_traits in GCC.
    using difference_type = std::ptrdiff_t;

    using pointer = value_type *;

    using reference = value_type &;

    single_iterator(Link *p) : pCur(p) {}

    T * operator-> () const { return cur(); }

    T * operator* () const { return cur(); }

    single_iterator & operator++ ()
    {
        this->MoveNext();

        return *this;
    }

    single_iterator operator++ (int)
    {
        single_iterator tmp = *this;

        this->MoveNext();

        return tmp;
    }

    bool operator == (const single_iterator & r) const
    {
        return this->link() == r.link();
    }

    bool operator != (const single_iterator & r)  const
    {
        return !(*this == r);
    }

private:

    //! Results in undefined behavior if the iterator is end().
    T * cur() const { return static_cast<T *>(pCur); }

    void MoveNext() { pCur = pCur->next(); }

    Link * link() const { return pCur; }

    Link * pCur;
};

然后我在容器中声明iteratorconst_iterator并实现begin()end()

template <class T,class Link,class Derived>
class container
{
public:

    using value_type = T *;

    using iterator = single_iterator<T,Link>;
    using const_iterator =  single_iterator<const T,const Link>;

    iterator begin() { return first(); }
    const_iterator begin() const { return first(); }
};

当我使用这样的迭代器时,它不会编译:

#include <iostream>
#include <vector>

struct A
{
    void func()
    {
        container<A>::const_iterator i = m_v.begin();
    }

    container<A> m_v;
};

int main()
{
    A a;

    a.func();

    return 0;
}

因为不能从const_interator构造iterator

通过最少的代码重复并为const_iteratoriterator定义单独的类来实现此转换的正确方法是什么?

请参见the same code with std::vector

EDIT1 :类似这样的代码

struct A
{
    operator A() { return *this;}
};

int main()
{
    A a;

    return 0;
}

因此可以通过添加const来定义类型转换运算符,并且const_iterator将转换为自身。但是看起来有点奇怪...

解决方法

您只需提供一个隐式转换运算符,即可将迭代器的非const版本转换为const版本。一个简短的例子:

template<class T>
class my_iter
{
public:
    // Non-const iterator can be implicitly converted to const
    operator my_iter<const T>() const {
        // Replace this with however your iterator is constructed
        return {};
    }
};

编辑: 该解决方案不允许典型的比较运算符在const和非const迭代器之间进行互操作,这是一个问题。解决方法是强制比较运算符仅接受const迭代器作为参数。传递非const迭代器时,它将隐式使用转换运算符。例子:

bool operator==(const my_iter<std::add_const_t<T>> & p_other) const 
{
    // Compare...
}

这还有一个缺点,即无法访问参数的private。一种解决方法是将iterator<const T>设为friend class的{​​{1}}:

iterator<T>

另一种方法是将#include <type_traits> template<class T> class my_iter { public: // Non-const iterator can be implicitly converted to const operator my_iter<const T>() const { // Replace this with however your iterator is constructed return {}; } bool operator==(const my_iter<std::add_const_t<T>> & p_other) const { return state == p_other.state; // Works even if `state` is `private` } private: // Some iterator implementation detail T * state = nullptr; // `iter<T>` and `iter<const T>` are friends of each other friend class my_iter<std::remove_const_t<T>>; friend class my_iter<std::add_const_t<T>>; }; 显式转换为*this,并仅使用iterator<const T>&来为operator==实现iterator<T>,这两个对象的私有成员都可以访问。

iterator<T>

使用任何一种解决方案,都可以对bool operator==(const my_iter<std::add_const_t<T>> & p_other) const { if constexpr (std::is_same_v<std::decay_t<decltype(p_other)>,my_iter<T>>) { // `*this` and `p_other` are both `const T` iterators // You may access the private members of both objects here return state == p_other.state; // Works even if `state` is `private` } else { // The `p_other` is not the same type as `*this` return static_cast<const my_iter<const T> &>(*this) == p_other; } } 进行重复。您可以从operator<构建为其他比较运算符。例如,operator<可以实现为operator>(a,b),而return b < a;可以实现为operator==(a,b)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。