C++ 如何在begin()和end()之外实现cbegin()和cend()?

C++ 如何在begin()和end()之外实现cbegin()和cend()?,c++,iterator,C++,Iterator,所以我有一个容器,我为它定义了自己的迭代器。在我的例子中,它是一个熟练工人,但类型并不重要 我实现了begin()和end(),我想知道如何实现cbegin()和cend() 有没有办法将迭代器转换为常量迭代器 下面是我的简化实现: class Skiplist { public: using key_type = int; using mapped_type = int; using value_type = std::pair<const key_type, m

所以我有一个容器,我为它定义了自己的迭代器。在我的例子中,它是一个熟练工人,但类型并不重要

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

有没有办法将迭代器转换为常量迭代器

下面是我的简化实现:

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] };
}

一个简单的解决方案是将
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;
};

一个简单的解决方案是将
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;
};


const\u迭代器
类型需要一个(可能是隐式的)构造函数,它接受一个
iterator
,或者您的
iterator
类型需要一个(可能是隐式的)cast操作符来
const\u迭代器
。实际上,这两种类型之间不存在允许转换的关系。因此,基本上我需要一个不显式的复制构造函数?使用从迭代器到常量迭代器的隐式复制(或移动)构造函数,您可以使您的cbegin/cend仅包装begin/end,返回常量迭代器。这是我能想到的重复最少的方法,代价是复制/移动构造函数,它可能会被优化掉。@Sandro4912不,
const\u迭代器
的复制构造函数将允许您从另一个
const\u迭代器
复制,但不能从
迭代器
复制。为此,
iterator
必须已经隐式转换为
const\u iterator
(这是第一个目标)。您需要一个隐式
常量迭代器(迭代器)
构造函数,它不是复制构造函数。@FrançoisAndrieux使用了正确的术语。。。它不是一个复制构造函数,只是一个构造函数。未复制
迭代器
const\u迭代器
正在从中构造。
const\u迭代器
类型将需要一个(可能是隐式的)构造函数,该构造函数接受单个
迭代器
,或者您的
迭代器
类型将需要一个(可能是隐式的)cast运算符来转换
const\u迭代器
。实际上,这两种类型之间不存在允许转换的关系。因此,基本上我需要一个不显式的复制构造函数?使用从迭代器到常量迭代器的隐式复制(或移动)构造函数,您可以使您的cbegin/cend仅包装begin/end,返回常量迭代器。这是我能想到的重复最少的方法,代价是复制/移动构造函数,它可能会被优化掉。@Sandro4912不,
const\u迭代器
的复制构造函数将允许您从另一个
const\u迭代器
复制,但不能从
迭代器
复制。为此,
iterator
必须已经隐式转换为
const\u iterator
(这是第一个目标)。您需要一个隐式
常量迭代器(迭代器)
构造函数,它不是复制构造函数。@FrançoisAndrieux使用了正确的术语。。。它不是一个复制构造函数,只是一个构造函数。未复制
迭代器
。一个
const\u迭代器
正在从中构造。请注意,继承
std::iterator
将是一个好主意。因此,您的意思是从标准前向迭代器中继承我在迭代器中的大部分内容,或者重新编写您的第二个片段
return Skiplist::iterator{current\u position->next[0]}
不是必需的null ptr它也可以是下一个元素。你的意思是我只是返回nullptr来表示结束。因为
nullptr
nullptr
?之前的循环条件是,它不会停止迭代,直到
current_position->next[0]
是nullptr。这是标记链表结尾的常用方法。标准正向迭代器仅用于定义STL中使用的迭代器的特征。请注意,继承
std::iterator
将是一个好主意。因此,您的意思是,我的迭代器中的大部分内容都是从标准正向迭代器继承来的,或者第二个代码段
返回Skiplist::迭代器{current_position->next[0]}
不是必需的null ptr它也可以是下一个元素。你的意思是我只是返回nullptr来表示结束。因为
nullptr
nullptr
?之前的循环条件是,它不会停止迭代,直到
current_position->next[0]
是nullptr。这是标记链表结束的常用方法。标准正向迭代器仅用于定义STL中使用的迭代器的特征。
while (current_position->next[0] != nullptr)
    current_position = current_position->next[0];

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