Оба этих кода недействительны (допустим только последний), но ваш компилятор (который не соответствует) только диагностирует один.Как говорит другой ответ, для этого используется введенное имя класса.Считается, что класс S
имеет имя члена S
, обозначающее этот же класс.Например (обратите внимание, что ключевое слово «class» перед 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, это может быть связано с изменением , введенным с GCC4.5:
G ++ теперь реализует DR 176. Ранее G ++ не поддерживал использованиеinjected-class-name базового класса шаблона в качестве имени типа, и поиск имени нашел объявление шаблона во вложенной области видимости.Теперь поиск имени находит имя введенного класса, которое можно использовать как тип или как шаблон, в зависимости от того, следует ли за именем список аргументов шаблона.В результате этого изменения, некоторый ранее принятый код может быть некорректно сформирован, потому что
- Имя введенного класса недоступно, потому что оно из частной базы, или
- Введенное имя класса нельзя использовать в качестве аргумента для параметра шаблона шаблона.
В любом из этих случаев код можно исправить, добавив спецификатор вложенного имени для явного именишаблон.Первый можно обойти с помощью -fno-access-control;второе отклоняется только с -pedantic.
Чтобы получить больше удовольствия от введенных имен классов - обратите внимание, что введенное имя класса не эквивалентно typedef, как можно подумать первым.Имя внедренного класса является именем класса, но не классифицируется как имя typedef, что означает, что оно может быть скрыто именами функций, объектов или перечислителей:
// valid, the data-member hides the injected class name
struct S { int S; };
Ссылка на имя внедренного классаВы можете сказать class S::S
(аналогично, в списке базовых классов имена не-типов игнорируются, поэтому вам не нужны особые предварительные предостережения), но простой поиск S::S
будет ссылаться на член-данные,