Ответ 1
Вкратце: в результате специализации Z
вводится введенное имя класса ::Z
, которое находится перед шаблоном псевдонимов. Однако если A
является шаблоном, имя введенного класса больше не найдено, потому что базовый класс B
зависит.
Рассмотрим [temp.local]/1:
Как обычные (не шаблонные) классы, шаблоны классов имеют injected-class-name (пункт 9). Можно использовать имя впрыскиваемого класса в качестве имени шаблона или имени типа.
И [basic.lookup]/3:
Введенное имя класса класса (раздел 9) также считается членом этого класса для целей поиска [...] lookup.
Z
рассматривается как неквалифицированное имя; [Basic.lookup.unqual]/7:
Таким образом, имя введенного класса Z
найдено как член базового класса Z<B, int>
и используется как имя-шаблон, что делает вашу вторую программу плохо сформированной. Фактически, ваш первый фрагмент использует имя введенного класса, а следующий фрагмент не будет компилироваться:
struct A
{
using Z = ::Z<float>;
struct B : ::Z<int>
{
static_assert( std::is_same<Z, ::Z<float>>{}, "" );
};
};
Наконец, если A
сделан шаблон, обратите внимание, что B
является зависимым типом в соответствии с [temp.dep.type]/(9.3) 1 поэтому Z<B>
зависимый тип в соответствии с [temp.dep.type]/(9.7), поэтому базовый класс Z<B>
не рассматривается во время поиска для неквалифицированного-id Z
в соответствии с [temp.dep ]/3:
В определении класса [..] область действия зависимый базовый класс (14.6.2.1) не рассматривается при неквалифицированных поиск имени либо в точке определения шаблона класса, либо член или во время создания шаблона или члена класса.
Следовательно, имя введенного класса не будет найдено.
1B
- это "вложенный класс [..], который является зависимым членом текущего экземпляра" (выделение мое), поскольку
Имя является зависимым членом текущего экземпляра, если оно является член текущего экземпляра, который, когда он смотрит вверх, ссылается на хотя бы один член класса, который является текущим экземпляром.