出于练习的考虑,我决定实现一个带有关联的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;
}
它适用于非指针类型,但不适用于指针类型。
我在这里误解了什么关键思想-我的迭代器应该反对吗 不处理节点指针?还是有办法使另一个过载 运算符可以方便地处理指针和非指针类型?
我还注意到编写模板代码时通常会遇到类似的问题。大多数时候,我想根据数据是否为指针来对数据进行不同的处理。
编辑 这是一些例子
给出一个结构:
struct FScanHit
{
unsigned long TimeStamp;
uint16_t Distance;
uint8_t Angle;
};
上课:
class Object
{
public:
void Update();
}
试图管理FScanHit列表和Object *列表:
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
答案 0 :(得分:1)
Exibit A:
template <class T> T foo() { ... }
foo<Object*>()->Update()
进行类型检查,而foo<Object>()->Update()
不进行类型检查,因为foo<Object>()
不是指向类类型对象的指针—它是一个类类型对象。
附件B:
template <class T> T* foo() { ... }
现在foo<Object>()->Update()
会进行类型检查,而foo<Object*>()->Update()
不会,因为
foo<Object*>()
不再是指向类类型对象的指针,而是指向指针的指针。
您的operator->()
存在完全相同的问题。
要使用哪个版本?
如果用operator*()
补充第二个版本(返回指针),则可以使用objectsIt->Update()
或(*objectsIt)->Update()
,这取决于您是否有指针。嗯,看起来很熟悉。 objectsIt
的语法是否与普通指针类似?好吧,这正是迭代器应该做的!