2016-10-26 2 views
1

je suis tombé sur ce code récemment, dans le contexte des listes intrusives:Quelle est la signification des arguments de modèle de ce type - `ClassA <T> T :: * ELEM`?

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

Je vois un code similaire dans le coup de pouce intrusive list library (member_hook<class T, class Hook, Hook T::* PtrToMember>).

Ma question concerne l'argument modèle Node<T> T::*NODE. Je ne suis pas un expert en C++, mais je n'ai jamais rencontré cette syntaxe particulière auparavant, et je ne sais pas quoi chercher pour le comprendre.

Qu'est-ce que cela signifie? Quel est son but, et que dois-je interpréter comme - "NODE est un pointeur vers un nœud, appartenant à T"? Cela n'a pas de sens pour moi, parce que T n'est pas connu pour contenir des membres spécifiques à l'avance, et autant que je sache, :: est utilisé pour résoudre la portée.

De même, si quelqu'un pouvait clarifier l'utilisation de *NODE dans cette ligne, par exemple: Node<T> *node = &(elem->*NODE);, cela m'aiderait à comprendre à quoi cela sert.

Répondre

3

C'est un pointeur de membre. NODE est un pointeur vers un membre de T qui a le type Node<T>.

De même, foo->*bar est un raccourci pour (*foo).*bar.* est l'opérateur de déréférencement-pointeur-à-membre. elem->*NODE accède au membre de *elem pointé par NODE.

+0

est-il attendu que T ait un membre de type Node ? – aspen100

+1

@ aspen100 Oui, c'est le bit intrusif. Pour être utilisable en tant qu'élément 'List',' T' doit contenir un membre 'Noeud ' quelque part. L'emplacement de ce membre est spécifié par le pointeur de membre 'NODE'. – melpomene

1

Cela s'appelle "pointeur vers l'opérateur membre".

La norme (N3690, section 5.5) dit:

Les opérateurs pointeur à membre -> * et * groupe de gauche à droite.. L'opérateur binaire. * Lie son deuxième opérande, qui doit être de type "pointeur vers le membre de T" à son premier opérande, qui doit être de classe T ou d'une classe dont T est une base non ambiguë et accessible. classe. Le résultat est un objet ou une fonction du type spécifié par le second opérande. L'opérateur binaire -> * lie son deuxième opérande, qui doit être de type "pointeur vers un membre de T" à son premier opérande, qui doit être de type "pointeur vers T" ou "pointeur vers une classe dont T est une classe de base non ambiguë et accessible. "L'expression E1 -> * E2 est convertie en la forme équivalente (* (E1)). * E2.

Regardez également http://en.cppreference.com/w/cpp/language/operator_member_access. L'opérateur :: * est le même - accès en utilisant le nom de classe au lieu d'une variable, un peu comme lorsque vous avez la classe C et l'objet obj vous pouvez soit faire C: func ou obj.func ou (& obj) -> func.