Это дополнительный вопрос.
в предыдущий вопрос, @ JohannesSchaub-litb сказал, что следующий код не полностью соответствует стандартам:
class { int i; }; //unnamed-class definition. § 9/1 allows this!
а потом он добавил,
хотя он грамматически действителен, он нарушает правило, согласно которому такой класс должен объявлять хотя бы одно имя в своей области действия.
Я не мог этого понять. Какое имя он говорит?
Может ли кто-нибудь более подробно остановиться на этом (желательно со ссылкой на Стандарт)?
Статья 9 стандарта позволяет class {public: int i;}
(обратите внимание на отсутствие последней точки с запятой), потому что это Децл-спецификатор-сл для безымянного класса может использоваться другая конструкция, такая как typedef или объявление переменной. Проблема с class {public: int i;};
(обратите внимание, что последняя точка с запятой теперь присутствует) заключается в том, что эта спецификация класса теперь становится объявлением. Это незаконная декларация в соответствии с пунктом 7 пункта 3 стандарта:
В таких случаях и за исключением объявления безымянного битового поля (9.6), Децл-спецификатор-сл должен ввести одно или несколько имен в программу или переименовать имя, введенное предыдущим объявлением.
Дело в том, что, объявив class{ int i; };
вы собираете кучу символов (int i
в этом случае) вы не сможете использовать где-либо еще в любом коде.
Чтобы этот код имел смысл, вы должны по крайней мере выполнить одно из следующих действий:
class Myclass { int i; }; //I can furthermore instantiate variables of Myclass
class { int i; } myvar; //This in fact creates a myvar object
typedef class { int i; } MyType; //I can funthermore instantiate variables of MyType
Говоря просто class{ int i; };
вы говорите компилятору:
int
и назовите это i
,class
Я никогда не позвоню и …};
)Если вы удалите это объявление из вашей программы, ничего не изменится.
class { int i; };
не является действительным объявлением, потому что это простая декларация без INIT-описатель-лист но это не вводит (или повторно объявляет) имя класса.
ИСО / МЭК 14882: 2011 7 [dcl.dcl] / 3:
В простая декларация, необязательный INIT-описатель-лист может быть опущено только при объявлении класса (раздел 9) или перечисления (7.2), то есть когда Децл-спецификатор-сл содержит либо класса спецификатор, elaboratedtype спецификатор с класс-ключ (9.1) или перечисление спецификатор. В этих случаях и всякий раз, когда класса спецификатор или же перечисление спецификатор присутствует в Децл-спецификатор-сл, идентификаторы в этих спецификаторах находятся среди имен, объявленных объявлением (как Класс-имена, перечисляемые-имена, или же нумераторы, в зависимости от синтаксиса). В таких случаях и за исключением объявления безымянного битового поля (9.6), Децл-спецификатор-сл должен ввести одно или несколько имен в программу или переименовать имя, введенное предыдущим объявлением.
Сообщение об ошибке от GCC объясняет это довольно кратко:
$ cat > a.cc
class { int i; };
$ g++ -Wall -std=c++98 a.cc
a.cc:1: error: abstract declarator ‘<anonymous class>’ used as declaration
class { int i; }
является абстрактно-описатель (Стандарт, § 8), но не действительный декларация (§ 7). Это правило, на которое ссылается @ JohannesSchaub-litb: для правильного объявления вам нужно что-то объявить, например, имя класса или имя переменной.
Вы нарушаете [basic.scope.pdecl]/6
, который говорит:
Точка объявления класса, впервые объявленного в подробном спецификаторе типа, следующая:
— для декларации формы
class-key attribute-specifier-seqopt identifier ;
идентификатор объявляется как имя класса в области, содержащей объявление, в противном случае
— для уточненного спецификатора типа формы
class-key identifier
если разработанный-тип-спецификатор используется в decl-спецификатор-seq или параметр-объявление-предложение
функция определена в области имен, идентификатор объявлен как имя класса в пространстве имен,
содержит декларацию; в противном случае, за исключением объявления друга, идентификатор объявляется в
наименьшее пространство имен или область блока, которая содержит объявление. [Примечание: эти правила также применяются в
шаблоны. — примечание конца] [Примечание: другие формы разработанного спецификатора типа не объявляют новое имя,
и поэтому должен ссылаться на существующее имя типа. См. 3.4.4 и 7.1.6.3. — конец примечания]
Есть еще один пример (в [basic.def]/2
) из стандарта, подтверждающего, что ваш пример не соответствует стандарту:
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
int x; // defines non-static data member x
static int y; // declares static data member y
X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up, down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX
Ваш пример не определяет ничего (кроме анонимной структуры, к которой нельзя получить доступ).
Обратите внимание на исключение для перечисления, потому что в этом случае вводятся два значения.