1

I came across this code recently, in the context of intrusive lists:

template<typename T> struct Node{
    T *next;
    T *prev;
    Node(): next(nullptr), prev(nullptr){}
};


/*
 * Intrusive doubly-linked-list
 *
 * */
template<typename T, Node<T> T::*NODE>
class List{
T *head;
T *tail;
public: 
    List():head(nullptr), tail(nullptr){}
    ~List() {clear();}

    /*
    * Add an element at the head of list
    * @param elem item to be inserted
    * */
    void add_to_front(T *elem){

        Node<T> *node = &(elem->*NODE);

        assert((node->next) == nullptr);
        assert((node->prev) == nullptr);

        node->next = head;

        if(head != nullptr){
            Node<T> *temp = &(head->*NODE);
            temp->prev = elem;
        }

        head = elem;

        if(tail == nullptr)
            tail = head;

    }
    //other member functions ,etc.
    ..
    ..
};

I see similar code in the boost intrusive list library (member_hook<class T, class Hook, Hook T::* PtrToMember>).

My question is regarding the template argument Node<T> T::*NODE. I am not an expert in C++, but I have never come across this particular syntax before, and don't know what to search for to understand it.

What does it mean? What is its purpose, and what should I interpret it as - "NODE is a pointer to a Node, belonging to T"? That doesn't make sense to me, because T isn't known to contain specific members ahead of time, and as far as I know, :: is used to resolve scope.

As well, if someone could clarify the use of *NODE in this line, for instance : Node<T> *node = &(elem->*NODE);, that would help me understand what this is being used for.

Simon
  • 1,756
  • 12
  • 8
aspen100
  • 965
  • 11
  • 22

2 Answers2

3

It's a member pointer. NODE is a pointer to a member of T that has type Node<T>.

Similarly, foo->*bar is shorthand for (*foo).*bar where .* is the dereference-pointer-to-member operator. elem->*NODE accesses the member of *elem pointed to by NODE.

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • is it then expected for T to have a member of type Node? – aspen100 Oct 26 '16 at 20:50
  • 1
    @aspen100 Yes, that's the intrusive bit. To be usable as a `List` element, `T` must contain a `Node` member somewhere. The location of this member is specified by the `NODE` member pointer. – melpomene Oct 26 '16 at 20:52
1

That's called "pointer to member operator".

The standard (N3690, section 5.5) says:

The pointer-to-member operators ->* and .* group left-to-right.

The binary operator .* binds its second operand, which shall be of type “pointer to member of T” to its first operand, which shall be of class T or of a class of which T is an unambiguous and accessible base class. The result is an object or a function of the type specified by the second operand.

The binary operator ->* binds its second operand, which shall be of type “pointer to member of T” to its first operand, which shall be of type “pointer to T” or “pointer to a class of which T is an unambiguous and accessible base class.” The expression E1->*E2 is converted into the equivalent form (*(E1)).*E2.

Also have a look at http://en.cppreference.com/w/cpp/language/operator_member_access.

The operator ::* is the same -- accessing using class name instead of a variable, much like when you have class C and object obj you can either do C::func or obj.func or (&obj)->func.

Donghui Zhang
  • 1,133
  • 6
  • 8