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

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

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

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

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

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

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

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

43

Решение

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

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

50

Другие решения

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

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

26

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

ИСО / МЭК 14882: 2011 7 [dcl.dcl] / 3:

В простая декларация, необязательный INIT-описатель-лист может быть опущено только при объявлении класса (раздел 9) или перечисления (7.2), то есть когда Децл-спецификатор-сл содержит либо класса спецификатор, elaboratedtype спецификатор с класс-ключ (9.1) или перечисление спецификатор. В этих случаях и всякий раз, когда класса спецификатор или же перечисление спецификатор присутствует в Децл-спецификатор-сл, идентификаторы в этих спецификаторах находятся среди имен, объявленных объявлением (как Класс-имена, перечисляемые-имена, или же нумераторы, в зависимости от синтаксиса). В таких случаях и за исключением объявления безымянного битового поля (9.6), Децл-спецификатор-сл должен ввести одно или несколько имен в программу или переименовать имя, введенное предыдущим объявлением.

11

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

10

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

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

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

если разработанный-тип-спецификатор используется в decl-спецификатор-seq или параметр-объявление-предложение
функция определена в области имен, идентификатор объявлен как имя класса в пространстве имен,
содержит декларацию; в противном случае, за исключением объявления друга, идентификатор объявляется в
наименьшее пространство имен или область блока, которая содержит объявление. [Примечание: эти правила также применяются в
шаблоны. — примечание конца] [Примечание: другие формы разработанного спецификатора типа не объявляют новое имя,
и поэтому должен ссылаться на существующее имя типа. См. 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

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

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

3
По вопросам рекламы [email protected]