所以我有一个容器,我为此定义了自己的迭代器。在我的示例中,它是一个“跳过列表”,但类型并不重要。
我实现了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] };
}
cbegin
和cbegin
非常重复。所以问题是,将迭代器转换为const_iterator缺少什么。我尝试了
const_cast
和static_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
}
最佳答案
一个简单的解决方案是在您的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] };