Оба этих кода недействительны (только последний действителен), но ваш компилятор (который не соответствует) только диагностирует один. Как говорится в другом ответе, это использует введенное имя класса. Класс S
считается членом-членом S
, обозначающим этот же класс. Например (обратите внимание на «класс» ключевое слово, прежде чем S::S
в первом примере, необходимо, чтобы заставить ссылку на нагнетаемой имя класса, а не конструктор по умолчанию):
class S { };
class S::S object; // creates an S object
class X : S::S::S::S { }; // derives from class S
Шаблоны классов также имеют впрыскивается имя класса. Как и введенное имя класса, он наследуется к производным классам, и поэтому ST<int>
плохо сформирован, потому что он использует это введенное имя класса, которое, однако, недоступно. Если вы используете GCC менее 4,5, он может иметь что-то делать с change introduced с GCC4.5:
G ++ в настоящее время реализует DR 176. Ранее G ++ не поддерживает использование впрыскиваемого-классовое имя шаблона базового класса как имя типа, и поиск имени нашел объявление шаблона в охватывающей области. Теперь поиск имени находит имя введенного класса, которое может использоваться либо как тип, либо как шаблон, в зависимости от того, следует ли за ним следовать список аргументов шаблона. В результате этого изменения, некоторый код, который ранее был принят, может быть плохо сформирован, потому что
- Вводимого-имя-класс не доступно, потому что это из частной базы, или
- Вводимых-классовых имя не может использоваться в качестве аргумента для параметра шаблона шаблона.
В любом из этих случаев код можно устранить, добавив спецификатор вложенного имени, чтобы явно указать шаблон. Первый может работать с -fno-access-control; второй отклоняется только с -андатикой.
Чтобы иметь немного больше удовольствия с инжектированных именами классов - обратите внимание, что впрыскивается имя класса не эквивалентно ЬурейеЕ, как можно было бы подумать в первую очередь. Вводимое имя класса является именем класса, но не классифицировано как имя-ЬурейиМ, что означает, что он может быть скрыта функцией, объект или нумератор имена:
// valid, the data-member hides the injected class name
struct S { int S; };
Чтобы обратиться к нагнетаемому имени класса вы можете скажем, class S::S
(аналогично, в списке базового класса игнорируются неигровые имена, поэтому вам не нужны специальные предостережения), но простой поиск до S::S
будет относиться к элементу данных.
Но тогда почему код работает с базовым классом шаблона? –