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