Почему класс { int i; }; не полностью соответствует стандарту?

Это дополнительный вопрос.

В предыдущем вопросе @JohannesSchaub-litb сказал, что следующий код < strong>не полностью соответствует стандарту:

class { int i; };  //unnamed-class definition. § 9/1 allows this!

а потом добавил,

в то время как это грамматически допустимо, это нарушает правило, согласно которому такой класс должен объявить по крайней мере одно имя в своей охватывающей области.

Я не мог этого понять. О каком имени он говорит?

Может ли кто-нибудь рассказать об этом подробнее (желательно со ссылкой на Стандарт)?


person Nawaz    schedule 30.10.2012    source источник
comment
О каком имени он говорит? Тот, которого нет. Объявление не объявляет имя класса, а также не объявляет имя typedef или переменную/функцию — ничего не добавляется к области, в которой объявление появляется в результате объявления.   -  person hmakholm left over Monica    schedule 30.10.2012
comment
Это эквивалент записи: int; в виде строки кода. Он называет тип, но не дает ему имени.   -  person jcoder    schedule 30.10.2012


Ответы (5)


Раздел 9 стандарта допускает class {public: int i;} (обратите внимание на отсутствие точки с запятой в конце), потому что этот decl-specifier-seq для безымянного класса может использоваться в какой-либо другой конструкции, такой как typedef или объявление переменной. Проблема с class {public: int i;}; (обратите внимание, что теперь присутствует последняя точка с запятой) заключается в том, что эта спецификация класса теперь становится объявлением. Это незаконное объявление согласно пункту 7, пункту 3 стандарта:

В таких случаях, за исключением объявления безымянного битового поля (9.6), decl-specifier-seq должен ввести в программу одно или несколько имен или повторно объявить имя, введенное предыдущее заявление.

person David Hammen    schedule 30.10.2012
comment
+1 за уточнение между decl-specifier-seq и объявлением. - person Thomas Matthews; 30.10.2012

Дело в том, что, объявляя 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 я никогда не позвоню и...
  • забудь это! (};)

Если вы удалите это объявление из своей программы, ничего не изменится.

person Emilio Garavaglia    schedule 30.10.2012
comment
Это все хорошо, но ИМХО нужно либо согласиться, либо не согласиться с тем, что этот код явно не соответствует стандарту. - person Jon; 30.10.2012
comment
Очевидно, что объявление класса бесполезно, но это не дает ответа на вопрос, разрешено ли это. Есть много бесполезных конструкций, разрешенных стандартом. Почему он получает так много голосов? - person interjay; 30.10.2012
comment
ОП запросил объяснение, а не соглашение (он сказал, что возможно ...) Согласно стандарту, каждая декларация должна что-то декларировать. Предлагаемый ничего не декларирует. Я могу понять, что ничто не может рассматриваться как что-то конкретное, но не допускается ли софизм (компилятор предполагает, что должно быть что-то забытое, а это может быть опасно) - person Emilio Garavaglia; 30.10.2012
comment
@Griwes: Возможно, вам следует проголосовать за то, ответило ли это на вопрос. - person interjay; 30.10.2012
comment
@interjay, я голосовал за это. И написал +1, как по хорошему, не голосую. Я различаю +1 и Upvote. - person Griwes; 30.10.2012

class { int i; }; не является допустимым объявлением, так как это простое объявление без списка_объявлений_инициализации, но оно не вводит (или повторно объявляет) имя класса.

ISO/IEC 14882:2011 7 [dcl.dcl] / 3:

В simple-declaration необязательный init-declarator-list может быть опущен только при объявлении класса (пункт 9) или перечисления (7.2), то есть когда decl-specifier-seq содержит либо спецификатор-класса, либо уточненный-спецификатор-типа с ключом-класса ( 9.1) или спецификатор перечисления. В этих случаях и всякий раз, когда спецификатор класса или спецификатор-перечисления присутствует в decl-specifier-seq, идентификаторы в этих спецификаторах среди имен, объявленных объявлением (как имена классов, имена перечислений или перечислители, в зависимости от синтаксиса). В таких случаях, за исключением объявления безымянного битового поля (9.6), decl-specifier-seq должен ввести в программу одно или несколько имен или повторно объявить имя введено предыдущим объявлением.

person CB Bailey    schedule 30.10.2012

Сообщение об ошибке от 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: для действительного объявления вам нужно что-то объявить, например. имя класса или имя переменной.

person Fred Foo    schedule 30.10.2012

Вы нарушаете [basic.scope.pdecl]/6, в котором говорится:

Точка объявления класса, впервые объявленного в уточненном спецификаторе типа, выглядит следующим образом:
— для объявления формы
class-key attribute-specifier-seqopt identifier ;

идентификатор объявляется как имя класса в области видимости, содержащей объявление, в противном случае
— для уточненного спецификатора типа вида
class-key identifier

если уточненный спецификатор-типа используется в decl-specifier-seq или в предложении-объявления параметра функции, определенной в области пространства имен, идентификатор объявляется как имя класса в пространстве имен, содержащем объявление; в противном случае, за исключением объявления друга, идентификатор объявляется в наименьшем пространстве имен или области блока, содержащей объявление. [Примечание: эти правила также применяются в шаблонах. — end note ] [Примечание: Другие формы уточненного спецификатора типа не объявляют новое имя и, следовательно, должны ссылаться на существующее имя типа. См. 3.4.4 и 7.1.6.3. — примечание в конце]

  1. вы не создаете переменную анонимного типа
  2. вы не создаете тип

Есть еще один пример (в [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

Ваш пример ничего не определяет (кроме анонимной структуры, чьи поля недоступны).

Обратите внимание на исключение для перечисления, потому что в этом случае используются два значения.

person BЈовић    schedule 30.10.2012