Итак, у меня есть контейнер, для которого я определяю свои собственные итераторы. В моем примере это Skiplist, но тип dowsnt имеет значение.
Я реализовал 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
, но явно не работает.
EDIT:
из комментария я попытался сделать неявный конструктор, но он все еще не кажется словом. Вот что я попробовал.
//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
}