Поисковый термин для дальнейшего исследования — двухэтапный поиск имени.
Короче говоря, компилятор пытается разрешить как можно больше имен, используемых шаблоном, в точке определения шаблона. Некоторые имена — так называемые зависимые имена — не могут быть разрешены на данном этапе и должны быть отложены до фактического создания экземпляра шаблона и определения его параметров. Грубо говоря, это имена, которые появляются из синтаксиса и зависят от параметров шаблона.
U
само по себе не является зависимым именем, поэтому компилятор пытается разрешить его при компиляции определения B
. В настоящее время он не может заглянуть внутрь A<T>
— он не знает, каким будет T
, и будет ли специализация A
для этого T
, которая может объявить или не объявить члена с именем U
. Затем поиск не находит объявления для U
, отсюда и ошибка.
U
в A<T>::U
является зависимым именем, его поиск откладывается до тех пор, пока не будет создан экземпляр B<int>
. В этот момент компилятор также создает экземпляр A<int>
и может искать внутри него объявление U
.
Вот почему вам нужно писать typename
в typename A<T>::U
. Компилятор не может искать объявление зависимого имени U
, но он должен знать, по крайней мере, должно ли оно быть типом или нетипом, так как от этого зависит низкоуровневый лексический анализ (классический пример: X*Y;
может быть проанализировано как объявление указателя или выражение с использованием умножения, в зависимости от того, является ли X
типом). Таким образом, правило состоит в том, что зависимое имя считается относящимся к нетипу, если ему не предшествует ключевое слово typename
.
person
Igor Tandetnik
schedule
24.04.2021