【问题标题】:Constructing const_iterator from iterator [duplicate]从迭代器构造 const_iterator [重复]
【发布时间】:2021-01-15 10:52:57
【问题描述】:

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

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 将转换为自身。不过看起来有点奇怪……

【问题讨论】:

  • 链接的重复提及转换中的一些答案从iteratorconst_iterator,但大多数没有,而且这个问题比这个问题更普遍。我不确定副本是否合适,但我不喜欢删除它,因为我已经发布了答案并且可能有偏见。
  • @FrançoisAndrieux 我想我添加了一条评论来解释哪些答案特别解决了它,但我现在看不到它。无论如何,尽管我认为这个问题是重复的,但您在下面的回答很好。

标签: c++


【解决方案1】:

您可以简单地提供一个隐式转换运算符,将您的迭代器的非常量版本转换为常量版本。一个简短的例子:

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...
}

这仍然有一个缺点,即参数的privates 不可访问。一种解决方法是使 iterator&lt;const T&gt; 成为 friend classiterator&lt;T&gt;

#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&lt;const T&gt;&amp;,并且只在iterator&lt;T&gt;iterator&lt;T&gt; 中实际实现operator==,其中两个对象的私有成员都可以访问。

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&lt; 重复。 Fromoperator&lt; 可以构造成其他比较运算符。例如operator&gt;(a, b)可以实现为return b &lt; a;operator==(a, b)可以实现为return !(a&lt;b) &amp;&amp; !(b&lt;a);

【讨论】:

  • 是的,这可能是实现这一点的正确方法......
  • std::enable_if&lt;..., !std::is_const... 的转换运算符怎么样?这可能消除了定义两个单独类的需要。
  • @Dmitriano 没必要。如果Tconst,那么转换运算符将永远不会发挥作用。编辑:我不确定您指的是哪两个单独的类。
  • 想通了!我定义了operator single_iterator&lt;const T, const Link&gt;() const
  • @Dmitriano 我已经修改了答案。我希望它能解决您的疑虑。
猜你喜欢
  • 2011-09-28
  • 2011-07-03
  • 1970-01-01
  • 1970-01-01
  • 2011-12-07
  • 1970-01-01
  • 2020-12-22
  • 2021-02-11
  • 1970-01-01
相关资源
最近更新 更多