我已经实现了这个侵入式链接列表:
template <class Entry>
struct LinkedListNode {
Entry *next;
Entry *prev;
};
template <class Entry, LinkedListNode<Entry> Entry::*NodeMember>
class LinkedList {
public:
void init ();
bool isEmpty () const;
Entry * first () const;
Entry * last () const;
Entry * next (Entry *e) const;
Entry * prev (Entry *e) const;
void prepend (Entry *e);
void append (Entry *e);
void insertBefore (Entry *e, Entry *target);
void insertAfter (Entry *e, Entry *target);
void remove (Entry *e);
public:
Entry *m_first;
Entry *m_last;
};
...
template <class Entry, LinkedListNode<Entry> Entry::*NodeMember>
inline Entry * LinkedList<Entry, NodeMember>::next (Entry *e) const
{
return (e->*NodeMember).next;
}
...
可以像这样使用:
struct MyEntry {
int value;
LinkedListNode<MyEntry> list_node;
};
LinkedList<MyEntry, &MyEntry::list_node> list;
list.init();
MyEntry entry1, entry2;
entry1.value = 3;
list.append(&entry1);
entry2.value = 5;
list.prepend(&entry2);
它可以正常工作,直到你需要两个包含彼此列表的对象:
struct MyEntry2;
struct MyEntry1 {
int value;
LinkedListNode<MyEntry1> node;
LinkedList<MyEntry2, &MyEntry2::node> list;
};
struct MyEntry2 {
int value;
LinkedListNode<MyEntry2> node;
LinkedList<MyEntry1, &MyEntry1::node> list;
};
每个MyEntry1都包含一个MyEntry2的列表,每个MyEntry2只能出现在一个MyEntry1的列表中;和相反的。但是,这不会编译,因为成员指针&amp; MyEntry2 :: node是在定义MyEntry2之前获取的:
prog.cpp:33:27: error: incomplete type 'MyEntry2' used in nested name specifier
prog.cpp:33:41: error: template argument 2 is invalid
这个有问题的布局实际上没有任何实用的语义,它只是我发现的一个理论问题,可能会限制通用链表的可用性。
有没有什么方法可以使这个列表更加不切实际?
编辑:此处所有数据结构的布局已完全定义。这是因为LinkedList的数据成员不依赖于有问题的NodeMember模板参数;只有功能。问题似乎是语言要求&amp; MyEntry2 :: node是已知的,即使它当时并不需要知道。
编辑:必须可以使用此通用列表将结构添加到两个或更多列表中;这是NodeMember模板参数的用途 - 它指定要使用条目中的哪个LinkedListNode。
答案 0 :(得分:2)
这是一个使用继承而不受影响的实现 你的问题。
template <typename Entry>
struct LinkedListNode {
Entry *next;
Entry *prev;
};
template <class Entry>
class LinkedList {
public:
void init ();
bool isEmpty () const;
Entry * first () const;
Entry * last () const;
Entry* next (Entry* e) const {
return e->next;
}
Entry * prev (Entry *e) const;
void prepend (Entry *e);
void append (Entry *e);
void insertBefore (Entry *e, Entry *target);
void insertAfter (Entry *e, Entry *target);
void remove (Entry *e);
public:
LinkedListNode<Entry> *m_first;
LinkedListNode<Entry> *m_last;
};
struct MyEntry2;
struct MyEntry1 : public LinkedListNode<MyEntry1> {
int value;
LinkedList<MyEntry2> list;
};
struct MyEntry2 : public LinkedListNode<MyEntry2> {
int value;
LinkedList<MyEntry1> list;
};
这是一个解决方案,其中LinkedList有一个仿函数作为第二个
模板参数。我们使用带有模板化的存取器函子
operator()
删除代码重复并延迟查找
名称。 注意:访问者实际上应该是成员并使用
空基优化。
template <class Entry>
struct LinkedListNode {
Entry *next;
Entry *prev;
};
template <class Entry, typename Func>
class LinkedList {
public:
void init ();
bool isEmpty () const;
Entry * first () const;
Entry * last () const;
Entry * next (Entry *e) const {
Func f;
return f(e).next();
}
Entry * prev (Entry *e) const;
void prepend (Entry *e);
void append (Entry *e);
void insertBefore (Entry *e, Entry *target);
void insertAfter (Entry *e, Entry *target);
void remove (Entry *e);
public:
Entry *m_first;
Entry *m_last;
};
struct MyEntry2;
struct node_m_access {
template <typename T>
LinkedListNode<T> operator()(T* t) const {
return t->node;
}
};
struct MyEntry1 {
int value;
LinkedListNode<MyEntry1> node;
LinkedList<MyEntry2, node_m_access> list;
};
struct MyEntry2 {
int value;
LinkedListNode<MyEntry2> node;
LinkedList<MyEntry1, node_m_access> list;
};
答案 1 :(得分:0)
这个问题等同于尝试:
struct MyEntry2;
struct MyEntry1 {
MyEntry2 a;
};
struct MyEntry2 {
MyEntry1 b;
};
在上面的例子中,编译器在生成MyEntry1时需要知道MyEntry2结构的大小。在您的情况下,编译器需要在生成MyEntry1时知道MyEntry2中节点的偏移量。
我在template-foo方面没有经验,但我猜想不是让Entry成为一个类,而是想使用指向类的指针。
答案 2 :(得分:0)
这是pmr的访问者解决方案的一个小修改,以减少样板量。诀窍是首先提供访问器的不完整的“struct”声明,用这些声明实例化LinkedList,然后通过继承模板访问器类来完成访问器。
template <class Entry>
struct LinkedListNode {
Entry *next;
Entry *prev;
};
template <class Entry, class Accessor>
class LinkedList {
public:
void init ();
bool isEmpty () const;
Entry * first () const;
Entry * last () const;
Entry * next (Entry *e) const {
return Accessor::access(e).next;
}
Entry * prev (Entry *e) const;
void prepend (Entry *e);
void append (Entry *e);
void insertBefore (Entry *e, Entry *target);
void insertAfter (Entry *e, Entry *target);
void remove (Entry *e);
public:
Entry *m_first;
Entry *m_last;
};
template <class Entry, LinkedListNode<Entry> Entry::*NodeMember>
struct LinkedListAccessor {
static LinkedListNode<Entry> & access (Entry *e)
{
return e->*NodeMember;
}
};
struct MyEntry2;
struct Accessor1;
struct Accessor2;
struct MyEntry1 {
int value;
LinkedListNode<MyEntry1> node;
LinkedList<MyEntry2, Accessor2> list;
};
struct MyEntry2 {
int value;
LinkedListNode<MyEntry2> node;
LinkedList<MyEntry1, Accessor1> list;
};
struct Accessor1 : LinkedListAccessor<MyEntry1, &MyEntry1::node> {};
struct Accessor2 : LinkedListAccessor<MyEntry2, &MyEntry2::node> {};
有了这个,当循环依赖没有问题时,甚至可以做一个便利类:
template <class Entry, LinkedListNode<Entry> Entry::*NodeMember>
class SimpleLinkedList
: public LinkedList<Entry, LinkedListAccessor<Entry, NodeMember> >
{};