Иерархический идентификатор типа С++
Рассмотрим следующий заголовочный файл:
template <typename T> struct tNode
{
T Data; //the data contained within this node
list<tNode<T>*> SubNodes; //a list of tNodes pointers under this tNode
tNode(const T& theData)
//PRE: theData is initialized
//POST: this->data == theData and this->SubNodes have an initial capacity
// equal to INIT_CAPACITY, it is set to the head of SubNodes
{
this->Data = theData;
SubNodes(INIT_CAPACITY); //INIT_CAPACITY is 10
}
};
Теперь рассмотрим строку кода из другого файла:
list<tNode<T>*>::iterator it(); //iterate through the SubNodes
Компилятор сообщает мне это сообщение об ошибке: Tree.h:38:17: error: need ‘typename’ before ‘std::list<tNode<T>*>::iterator’ because ‘std::list<tNode<T>*>’ is a dependent scope
Я понятия не имею, почему компилятор кричит на меня за это.
Ответы
Ответ 1
В list<tNode<T>*>::iterator
у вас есть зависимое имя, то есть имя, которое зависит от параметра шаблона.
Таким образом, компилятор не может проверить list<tNode<T>*>
(он не имеет определения в этой точке), и поэтому он не знает, является ли list<tNode<T>*>::iterator
либо статическим полем, либо типом.
В такой ситуации компилятор предполагает, что это поле, поэтому в вашем случае он дает синтаксическую ошибку. Чтобы решить проблему, просто сообщите компилятору, что это тип, поставив typename
перед объявлением:
typename list<tNode<T>*>::iterator it
Ответ 2
Во-первых, как уже отмечалось в других ответах, имена типов, вложенные в зависимые типы, должны быть добавлены с ключевым словом typename
.
Это ключевое слово не требуется, когда шаблон полностью специализирован, что означает, что list<tnode<int>*>::iterator
не нуждается в typename
, но когда внешний класс все еще зависит от параметра шаблона T
, должен присутствовать typename
.
template <typename T> void foo() {
list<tnode<int>*>::iterator it1; // OK without typename
typename list<tnode<T>*>::iterator it2; // typename necessary
}
Во-вторых, даже с typename
typename list<tNode<T>*>::iterator it();
Объявление объявит функцию, а не итератор. Удалите ()
.
Ответ 3
list<tNode<T>*>::iterator
- зависимое имя, тип которого зависит от параметра шаблона. Чтобы объявить эту переменную, вам нужно использовать ключевое слово typename
:
typename list<tNode<T>*>::iterator it = ...;
Ответ 4
Более подробное описание ответов приведено здесь
Описание ключевого слова typename для С++
У меня была другая, но схожая проблема в том, что я хотел набрать итератор для дочерних узлов с помощью:
typedef std::vector<NodeType*>::iterator ChildIterator;
который дал мне ту же ошибку компилятора. С предложениями здесь и с помощью приведенной выше ссылки решение моей проблемы заключается в использовании
typedef typename std::vector<NodeType*>::iterator ChildIterator;
вместо.