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