C/C++

Как написать итератор? для списка

Есть список (замкнутый, хвост указывает на голову, голова на хвост)

 template 
struct ListNode
{
ListNode(){}
~ListNode() {}
type m_data;
ListNode* m_left = 0;
ListNode* m_right = 0;
};

template
class List
{
public:
...
ListNode* m_head;
};

И вот как дальше делать?
У меня была попытка сделать так:

 class Iterator 
{
ListNode* m_node;
ListNode* m_nodeEnd;
bool m_isEnd;
public:
Iterator() :m_node(0), m_isEnd(true) {}
Iterator(ListNode* head) :m_node(head), m_isEnd(false)
{
if (!head)
{
m_isEnd = true;
}
else
{
m_nodeEnd = head->m_left;
}
}
~Iterator() {}

Iterator& operator ++() {
if (m_node == m_nodeEnd) {
m_isEnd = true;
}
m_node = m_node->m_right;
return *this;
}

bool operator ==(const Iterator& other) const {
if (m_isEnd != other.m_isEnd) return false;
return true;
}
bool operator !=(const Iterator& other) const {
if (m_isEnd != other.m_isEnd) return true;
return false;
}
const type& operator*() {
return m_node->m_data;
}
type* operator->() {
return m_node->m_data;
}
};

Iterator begin() {
return Iterator(m_head);
}
Iterator end() {
return Iterator();
}
Для того чтобы работало (в for например), надо определить, был ли достигнут конец. для этого добавил переменную

m_isEnd

Всё работает. Но я чую что сделано не правильно (мне даже стыдно показывать этот код). И как сделать const версию?
Не пойму в чем смысл кольцевой список рассматривать с позиции обычного (у которого есть начало и конец) и как вы собираетесь его применять? У вас по идее должны быть только ++ , -- , текущий элемент, размер и все. Никаких концов и начал. Пройти весь список - выполнить ++ или -- определенное число раз (соответствующее размеру).
Григорий Полтергейстов
Григорий Полтергейстов
51 417
Лучший ответ
1. Итератор должен быть вложенным классом в класс List, чтобы иметь доступ к его закрытым членам.
2. Метод operator++ должен возвращать новый итератор, а не ссылку на текущий объект.
3. Методы operator== и operator!= должны сравнивать указатели на текущие узлы, а не значения m_isEnd.
4. Для создания константной версии итератора можно использовать шаблонный класс с параметром const type и определить соответствующие методы cbegin и cend.

Вот пример константной версии итератора для вашего класса List:
 template  
class List
{
public:
...
ListNode* m_head;

class Iterator
{
ListNode* m_node;
ListNode* m_nodeEnd;
bool m_isEnd;
public:
Iterator() :m_node(0), m_isEnd(true) {}
Iterator(ListNode* head) :m_node(head), m_isEnd(false)
{
if (!head)
{
m_isEnd = true;
}
else
{
m_nodeEnd = head->m_left;
}
}
~Iterator() {}

Iterator& operator ++() {
if (m_node == m_nodeEnd) {
m_isEnd = true;
}
m_node = m_node->m_right;
return *this;
}

bool operator ==(const Iterator& other) const {
if (m_isEnd != other.m_isEnd) return false;
return true;
}
bool operator !=(const Iterator& other) const {
if (m_isEnd != other.m_isEnd) return true;
return false;
}

const type& operator*() {
return m_node->m_data;
}

const type* operator->() {
return &(m_node->m_data);
}

};

class ConstIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = const type;
using difference_type = std::ptrdiff_t;
using pointer = const type*;
using reference = const type&;

ConstIterator(ListNode* node) : current(node) {}

reference operator*() const {
return current->m_data;
}

pointer operator->() const {
return &(current->m_data);
}

ConstIterator& operator++() {
current = current->m_right;
return *this;
}

ConstIterator operator++(int) {
ConstIterator temp(*this);
++(*this);
return temp;
}

ConstIterator& operator--() {
current = current->m_left;
return *this;
}

ConstIterator operator--(int) {
ConstIterator temp(*this);
--(*this);
return temp;
}

friend bool operator==(const ConstIterator& a, const ConstIterator& b) {
return a.current == b.current;
}

friend bool operator!=(const ConstIterator& a, const ConstIterator& b) {
return a.current != b.current;
}

private:
ListNode* current;
};

Iterator begin() {
return Iterator(m_head);
}

Iterator end() {
return Iterator();
}

ConstIterator cbegin() const {
return ConstIterator(m_head);
}

ConstIterator cend() const {
return ConstIterator(nullptr);
}
};
Артур Примаков Где ты берёшь эту отборную ахинею?