C++ C++;具有侵入式链表的循环依赖

C++ C++;具有侵入式链表的循环依赖,c++,templates,linked-list,circular-dependency,intrusive-containers,C++,Templates,Linked List,Circular Dependency,Intrusive Containers,我已经实现了这个侵入式链表: template <class Entry> struct LinkedListNode { Entry *next; Entry *prev; }; template <class Entry, LinkedListNode<Entry> Entry::*NodeMember> class LinkedList { public: void init (); bool isEmpty () co

我已经实现了这个侵入式链表:

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;
}
...
这个有问题的布局实际上没有任何实际的语义,这只是我发现的一个理论问题,可能会限制通用链表的可用性

有没有什么方法可以避免这个列表变得更加不切实际

编辑:此处所有数据结构的布局都已完全定义。这是因为LinkedList的数据成员不依赖有问题的NodeMember模板参数;只有函数才可以。问题似乎在于,该语言要求&MyEntry2::node是已知的,尽管当时并不需要知道它


编辑:必须能够使用此通用列表将结构添加到两个或多个列表中;这是NodeMember模板参数的用途-它指定要使用条目中的哪个LinkedListNode。

此问题相当于尝试执行以下操作:

struct MyEntry2;

struct MyEntry1 {
    MyEntry2 a;
};

struct MyEntry2 {
    MyEntry1 b;
};
在上述情况下,编译器在生成MyEntry1时需要知道MyEntry2结构的大小。在您的例子中,编译器在生成MyEntry1时需要知道MyEntry2中节点的偏移量


我在模板foo方面没有经验,但我想,与其将条目设为类,不如使用指向类的指针。

下面是一个使用继承的实现,它不受 你的问题

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;
};

这里是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> {};
模板
结构LinkedListNode{
条目*下一步;
条目*prev;
};
模板
类链接列表{
公众:
void init();
bool-isEmpty()常量;
条目*第一个()常量;
条目*最后()常量;
条目*下一条(条目*e)常量{
返回访问器::access(e).next;
}
条目*prev(条目*e)const;
无效预结束(条目*e);
无效附加(条目*e);
void insertBefore(条目*e,条目*target);
无效插入符(条目*e,条目*目标);
无效删除(条目*e);
公众:
输入*m_优先;
条目*m_last;
};
模板
结构LinkedListAccessor{
静态LinkedListNode和访问(条目*e)
{
返回e->*节点成员;
}
};
结构MyEntry2;
结构访问器1;
结构访问器2;
结构MyEntry1{
int值;
LinkedListNode节点;
链接列表;
};
结构MyEntry2{
int值;
LinkedListNode节点;
链接列表;
};
结构访问器1:LinkedListAccessor{};
结构访问器2:LinkedListAccessor{};
这样,当循环依赖关系没有问题时,甚至可以创建一个便利类:

template <class Entry, LinkedListNode<Entry> Entry::*NodeMember>
class SimpleLinkedList
: public LinkedList<Entry, LinkedListAccessor<Entry, NodeMember> >
{};
模板
类SimpleLink列表
:公共链接列表
{};

请参见我的编辑。LinkedList的布局和大小可以在不知道NodeMember模板参数的情况下确定。毕竟,LinkedList只是一对指针(在声明不完整之后,指针的大小是已知的)。看看LinkedList的声明如何没有真正使用NodeMember。但是它不知道什么是
::node
,因为你没有定义
MyEntry2
。你发表评论时我正在编辑这个,如果你还不明白,请告诉我。重要的是对NodeMember*的访问,而不是LinkedList的大小。@DeadMG我知道它为什么不起作用。我问的是如何让它工作。嗯,你不能,因为你所做的是一个基本的循环依赖。我认为它确实需要在当时被了解。您引用的是一个尚未声明的成员,只是因为您尚未创建该结构的实例,并不意味着您的编译器在解析该行时没有查找该成员。当我只使用它的标识符而不是它的一个成员时,我只使用了结构的前向声明。也许我错了,但是循环依赖也让我感到困惑=py您也可以通过继承实现钩子。这将解决问题,而且在我看来更干净,不管怎样,它是侵入式的。另外,你能告诉我们为什么你不想使用STL列表吗?@CrazyCasta侵入式列表有很多理由。我不认为这在这里是必要的。@CrazyCasta这个问题不是关于侵入式和非侵入式数据结构的。我的问题是关于侵入性列表,无论出于何种原因。我没有研究boost intrusive,但我怀疑它们也有同样的问题。如何使结构成为多个独立链表的成员?成员指针参数的全部目的就是允许这种情况。@AmbrozBizjak您可能想将其添加到您的问题中。这是一个重要的要求。@AmbrozBizjak现在有了第二个解决方案,使用带有模板化的
运算符()的访问器函数。
。这很好,谢谢。我还做了一个小的修改,使它更易于使用(见我的答案)。
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;
};
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;
};
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> >
{};