Что означает аргументы шаблона этого типа - `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.
..
..
};
Я вижу похожий код в библиотеке интрузивных списков (member_hook<class T, class Hook, Hook T::* PtrToMember>
).
Мой вопрос касается аргумента шаблона Node<T> T::*NODE
, Я не эксперт в C++, но я никогда раньше не сталкивался с этим конкретным синтаксисом и не знаю, что искать, чтобы понять его.
Что это значит? Какова его цель, и что я должен интерпретировать как "NODE - это указатель на узел, принадлежащий T"? Это не имеет смысла для меня, потому что T, как известно, не содержит конкретных членов заранее, и, насколько я знаю, ::
используется для разрешения области.
А также, если кто-то мог бы уточнить использование *NODE
в этой строке, например: Node<T> *node = &(elem->*NODE);
, это помогло бы мне понять, для чего это используется.
2 ответа
Это указатель на член. NODE
это указатель на член T
это имеет тип Node<T>
,
Так же, foo->*bar
это сокращение для (*foo).*bar
где .*
является оператором разыменования-указателя на член. elem->*NODE
получает доступ к члену *elem
указал на NODE
,
Это называется "указатель на член оператора".
Стандарт (N3690, раздел 5.5) гласит:
Операторы указатель на член ->* и.* Группируются слева направо.
Бинарный оператор.* Связывает свой второй операнд, который должен иметь тип "указатель на член T", со своим первым операндом, который должен быть класса T или класса, для которого T является однозначным и доступным базовым классом. Результатом является объект или функция типа, указанного вторым операндом.
Бинарный оператор ->* связывает свой второй операнд, который должен иметь тип "указатель на член T", с его первым операндом, который должен иметь тип "указатель на T" или "указатель на класс, для которого T является однозначным и доступный базовый класс ". Выражение E1->*E2 преобразуется в эквивалентную форму (*(E1)).*E2.
Также посмотрите на http://en.cppreference.com/w/cpp/language/operator_member_access.
Оператор::* такой же - доступ с использованием имени класса вместо переменной, очень похоже на то, что когда у вас есть класс C и объект obj, вы можете сделать C::func или obj.func или (&obj)->func.