Зависимая область и вложенные шаблоны

Когда я скомпилирую это:

#ifndef BTREE_H #define BTREE_H #include  template  class btree { public: class node { public : node(); private: node* parent; QList values; QList children; }; public: btree(); void insert(const T& value); node* findLeaf(const T& value); void performInsertion(const T& value, node& place); // node* root; }; #endif // BTREE_H 

Реализация findLeaf заключается в следующем:

 template  btree::node* btree::findLeaf(const T &value) { if(root == NULL) return root; } 

Эта ошибка возникает:

  error: need 'typename' before 'btree::Node' because 'btree' is a dependent scope 

Грамматика C ++ является ужасающей, и, как таковая, при задании classа шаблона невозможно узнать, является ли ::node вы ссылаетесь, переменная / константа или тип.

Поэтому в Стандарте указано, что вы используете typename перед типами для устранения этой двусмысленности и обрабатываете все другие способы использования, как если бы это была переменная.

таким образом

 template  typename btree::node* btree::findLead(T const& value) ^~~~~~~~ 

является правильной сигнатурой для определения.

Нет, это не связано с грамматикой C ++, но с ленивым созданием шаблонов C ++ и двухфазным поиском.


В C ++ зависимое имя – это имя или символ, значение которого зависит от одного или нескольких параметров шаблона:

 template  struct Foo { Foo () { const int x = 42; T::Frob (x); } }; 

Разбирая этот fragment отдельно, не зная всех будущих значений T, компилятор C ++ не может определить, является ли frob в T именем функции, именем типа, чем-то другим или существует ли вообще.

Чтобы привести пример, почему это имеет значение, представьте себе некоторые типы, которые вы замените T:

 struct Vietnam { typedef bool Frob; // Frob is the name of a type alias }; struct Football { void Frob (int) {} // Frob is a function name }; struct BigVoid {}; // no Frob at all! 

Поместите их в наш шаблон Foo:

 int main () { Foo fv; // Foo::Foo would declare a type Foo ff; // Foo::Foo would make a function call Foo fbv; // Foo::Foo is not defined at all } 

Релевантно в этом заключается концепция двухфазного поиска . На первом этапе независимый код анализируется и компилируется:

 template  struct Foo { Foo () { const int x = 42; // does not depend on T T::Frob (x); // full check skipped for second phase, only rudimentary checking } }; 

Этот первый этап – это то, что позволяет компиляторам испускать сообщения об ошибках в самом определении шаблона.

Вторая фаза будет приводить к ошибкам вашего шаблона в сочетании с тогда известным типом T.

Некоторые ранние компиляторы C ++ будут анализировать только шаблоны только после их создания; с этими компиляторами, неоднозначность не нужна, поскольку в момент создания экземпляра аргументы шаблона известны. Проблема с этим однофазным поиском заключается в том, что многие ошибки в самом шаблоне не будут обнаружены вообще или только в конце компиляции, потому что шаблоны по умолчанию создаются лениво, т. Е. Расширяются только части шаблона classа, которые на самом деле используется, плюс он дает вам более загадочные сообщения об ошибках, которые могут быть root в аргументе шаблона.

Поэтому для того, чтобы двухфазный поиск работал, вы должны помочь компилятору. В этом случае вы должны использовать typename , чтобы сообщить компилятору, что вы имеете в виду тип:

 template  struct Foo { Foo () { const int x = 42; typename T::Frob (x); } }; 

Теперь компилятор знает, что x – это переменная типа Frob 🙂

  • Делают ли c ++ шаблоны медленными?
  • Что именно «нарушено» с помощью двухфазного экземпляра шаблона Microsoft Visual C ++?
  • Ограничить параметр шаблона C ++ для подclassа
  • Магические аргументы в шаблонах функций
  • Вызов шаблона с несколькими параметрами трубопровода
  • Строковые литералы не разрешены как параметры шаблона нестандартного типа
  • Проверьте, имеет ли class функцию-член определенной подписи
  • В чем различия между «родовыми» типами в C ++ и Java?
  • JQuery's $ находится в конфликте с StringTemplate.Net в ASP.Net MVC
  • Когда использовать std :: forward для пересылки аргументов?
  • Разница между экземпляром и специализацией в шаблонах c ++
  • Interesting Posts

    Обработка двоеточия в идентификаторе элемента с помощью jQuery

    Почему локальные передачи файлов медленнее, чем 1 Гбит / с / 100 Мбит / с

    Ошибка компилятора: «Инициализатор не является константой времени компиляции»

    Android Speech Recognition как услуга на Android 4.1 и 4.2

    Малиновый PI и экран для ноутбука

    Исключение OutOfMemory при загрузке растрового изображения из внешнего хранилища

    Ошибка с NSJSONSerialization – Недопустимый тип записи JSON (меню)

    Загрузка в Windows с USB-накопителя, созданного на OSX

    Таймер с высоким разрешением в C #

    ShouldSerialize * () vs * Условный шаблон условной сериализации

    Если / else в ANTLR с использованием прослушивателей

    Как я могу выполнить полную установку Cygwin с помощью нового установщика?

    Создание тепловой карты из панд DataFrame

    Как я могу проверить, доступна ли Sim-карта в устройстве Android?

    Можете ли вы ссылаться на хороший пример использования BackgroundWorker, не помещая его в форму как компонент?

    Давайте будем гением компьютера.