如何从begin()和end()中实现cbegin()和cend()?

时间:2018-07-05 18:36:07

标签: c++ iterator

所以我有一个容器,我为其定义了自己的迭代器。在我的示例中,它是一个跳过列表,但类型无关紧要。

我实现了begin()end(),但我想知道如何实现cbegin()cend()

是否可以将迭代器转换为const_iterator?

这是我的简化实现:

class Skiplist {
public:
    using key_type = int;
    using mapped_type = int;
    using value_type = std::pair<const key_type, mapped_type>;
    using size_type = std::size_t;

    template<typename IT> class iterator_base;          // template class for iterator and iterator const   

    using iterator = iterator_base<value_type>;
    using const_iterator = iterator_base<value_type const>;

    //....

    // Iterators
    iterator begin() noexcept;
    iterator end() noexcept;
    const_iterator cbegin() const noexcept;     // can this be made by convert iterator to const iterator?
    const_iterator cend() const noexcept;

    //....
private:
    struct Skipnode;                // forward declaration so Basenode can have Skiplist*

    struct Basenode {                                       // Empty node, mainly created to represent head element. 
                                                            // Is there a way to get a empty head with no key / values without using this ?
        Basenode(int in_level);
        Basenode(const std::vector<Skipnode*>& in_next);

        std::vector <Skipnode*> next;
    };

    struct Skipnode : Basenode {                        // derived so with Basenode* we can start the iteration of the node on head
        Skipnode(value_type val, int in_level);
        Skipnode(value_type val, const std::vector<Skipnode*>& in_next);

        value_type value;       // first key / second mapped type = value
    };

    //....
};


template<typename IT>
class Skiplist::iterator_base {
public:
    iterator_base(Skiplist::Skipnode* pos)
        : curr{ pos }
    {
    };

    //...

    IT& operator*() { return curr->value; }
    IT* operator->() { return &curr->value; }

private:


    Skiplist::Skipnode* curr;
};



Skiplist::iterator Skiplist::begin() noexcept
{
    if (head.next.empty()) return Skiplist::iterator{ nullptr };

    return Skiplist::iterator{ head.next[0] };
}

Skiplist::iterator Skiplist::end() noexcept
{
    if (head.next.empty()) return Skiplist::iterator{ nullptr };

    Basenode* current_position = &head;
    while (current_position->next[0] != nullptr)
        current_position = current_position->next[0];

    return Skiplist::iterator{ current_position->next[0] };
}

Skiplist::const_iterator Skiplist::cbegin() const noexcept
{
    if (head.next.empty()) return Skiplist::const_iterator{ nullptr };

    return Skiplist::const_iterator{ head.next[0] };
}

Skiplist::const_iterator Skiplist::cend() const noexcept
{
    if (head.next.empty()) return Skiplist::const_iterator{ nullptr };

    const Basenode* current_position = &head;
    while (current_position->next[0] != nullptr)
        current_position = current_position->next[0];

    return Skiplist::const_iterator{ current_position->next[0] };
}

它与cbegincbegin非常重复。

所以问题是,将迭代器转换为const_iterator缺少什么。我尝试了const_caststatic_cast,但是很遗憾,它没有用。

编辑: 从评论我试图做一个隐式的构造函数,但似乎仍然没有措辞。这是我尝试过的。

//the constructor in the iterator class:
        iterator_base(const iterator_base<IT>& it)
            : curr{ it.curr }
        {
        }

    Skiplist::const_iterator Skiplist::cbegin() const noexcept
    {
        if (head.next.empty())
            return Skiplist::const_iterator{ nullptr };

        return Skiplist::const_iterator{ begin() };     // this doesnt work
    }

1 个答案:

答案 0 :(得分:1)

一个简单的解决方案是在您的base_iterator中添加一个bool is_const模板参数,并根据该参数调整类型并禁用非常量访问。

示例代码:

template<typename IT, bool is_const> class iterator_base;

using iterator = iterator_base<value_type, /*is_const=*/false>;
using const_iterator = iterator_base<value_type, /*is_const=*/true>;

// ...

template<typename IT, boo is_const>
class Skiplist::iterator_base {
    public:
         using node_type = typename std::conditional<is_const, Skiplist::Skipnode const, Skiplist::Skipnode>::type;
         using value_type = typename std::conditional<is_const, IT const, IT>::type;

    iterator_base(node_type* pos) : curr{ pos }{};

    value_type & operator*() const { return curr->value; }
    value_type * operator->() const { return &curr->value; }

private:
    node_type* curr;
};

关于end()cend(),您可以简单地将iterator_base(nullptr)定义为字符串的结尾。您的代码没用:

while (current_position->next[0] != nullptr)
    current_position = current_position->next[0];

// ***** current_position->next[0] == nullptr ******
return Skiplist::iterator{ current_position->next[0] };
相关问题