Ради практики я решил реализовать контейнер списков со связанным объектом Iterator. Я раньше не реализовывал итераторы, но часто использовал шаблон. Объект итератора выглядит следующим образом:
template <typename DataType>
struct FNode
{
DataType Data;
FNode* Next;
FNode* Prev;
FNode(DataType _data, FNode* _next, FNode* _prev)
: Data(_data)
, Next(_next)
, Prev(_prev)
{
}
};
template <typename DataType>
struct TListIterator
{
TListIterator(FNode<DataType>* _Element)
: Element(_Element)
{
}
FNode<DataType>* Element;
// Some operators overload ....
// ....
DataType operator ->()
{
return Element->Data;
}
Итак, по сути, я хочу, чтобы итератор сохранил указатель узла в моем списке / контейнере. Моя проблема возникает при доступе к данным через итератор. Я хочу иметь возможность просто использовать оператор стрелки для прямого доступа к переменной DataType, содержащейся в узле.
Реализация выше работает нормально, если мой аргумент шаблона является указателем. Однако, если я решу использовать список, в котором хранится тип данных без указателя, оператор стрелки завершится ошибкой, поскольку я больше не возвращаю тип указателя. Само собой разумеется, если я изменю перегрузку оператора, чтобы возвратить указатель как это:
DataType* operator ->()
{
return &Element->Data;
}
Работает для типов без указателей, но не для типов указателей.
Какую ключевую идею я здесь неправильно понимаю - должен ли мой объект итератора
не иметь дело с указателями узлов? Или есть способ перегрузить другой
оператор для удобной работы с указателями и без указателей?
Я также замечаю, что обычно сталкиваюсь с подобными проблемами при написании кода шаблона. В большинстве случаев я хотел бы обрабатывать данные по-разному в зависимости от того, является ли он указателем или нет.
EDIT
Вот несколько примеров
С учетом структуры:
struct FScanHit
{
unsigned long TimeStamp;
uint16_t Distance;
uint8_t Angle;
};
Учитывая класс:
class Object
{
public:
void Update();
}
Попытка управления списком FScanHit и списком объектов *:
TList<FScanHit> scans;
TList<Object*> objects;
// Add elements to either lists
// ....
// Access the actual data
TListIterator<FScanHit> scanIt = scans.Begin(); // Begin uses the TListIterator constructor shown above to create an iterator whose element is the head node of the list
TListIterator<Object*> objectsIt = objects.Begin();
objectsIt->Update(); // Works, because ->() returns a pointer type Object*
uint8_t dist = scanIt->Distance; // Error: result of 'operator->()' yields non-pointer result