Why class { int i; }; is not fully standard-conformant?

谁说我不能喝 提交于 2019-11-27 11:54:24

问题


This is a follow-up question.

In the previous question, @JohannesSchaub-litb said that the following code is not fully standard-conformant:

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

and then he added,

while it is grammatically valid, it breaks the rule that such a class must declare at least one name into its enclosing scope.

I couldn't really understand this. What name is he talking about?

Could anyone elaborate on this further (preferably quoting the Standard)?


回答1:


Clause 9 of the standard allows class {public: int i;} (note the lack of a final semicolon) because this decl-specifier-seq for an unnamed class might be used in some other construct such as a typedef or a variable declaration. The problem with class {public: int i;}; (note that the final semicolon is now present) is that this class specification now becomes a declaration. This is an illegal declaration per clause 7, paragraph 3 of the standard:

In such cases, and except for the declaration of an unnamed bit-field (9.6), the decl-specifier-seq shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration.




回答2:


The point is that by declaring class{ int i; }; you are assembling a bunch of symbol (int i, in this case) you will not be able to use anywhere else in whatever code.

For this code to make sense you should at least do one of the following:

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

By saying just class{ int i; }; you are saying to the compiler:

  • keep an int and name it i,
  • wrap it into a class I'll never call and...
  • forget it! (};)

If you remove that declaration from your program, nothing will change.




回答3:


class { int i; }; is not a valid declaration because it is a simple-declaration without an init-declarator-list but it doesn't introduce (or re-declare) a class name.

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

In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause 9) or enumeration (7.2), that is, when the decl-specifier-seq contains either a class-specifier, an elaboratedtype-specifier with a class-key (9.1), or an enum-specifier. In these cases and whenever a class-specifier or enum-specifier is present in the decl-specifier-seq, the identifiers in these specifiers are among the names being declared by the declaration (as class-names, enum-names, or enumerators, depending on the syntax). In such cases, and except for the declaration of an unnamed bit-field (9.6), the decl-specifier-seq shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration.




回答4:


The error message from GCC explains it quite succinctly:

$ 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; } is an abstract-declarator (Standard, §8) but not a valid declaration (§7). That's the rule that @JohannesSchaub-litb referenced: for a valid declaration, you need something to be declared, e.g. a class name or variable name.




回答5:


You are breaking the the [basic.scope.pdecl]/6, which says :

The point of declaration of a class first declared in an elaborated-type-specifier is as follows:
— for a declaration of the form
class-key attribute-specifier-seqopt identifier ;

the identifier is declared to be a class-name in the scope that contains the declaration, otherwise
— for an elaborated-type-specifier of the form
class-key identifier

if the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a function defined in namespace scope, the identifier is declared as a class-name in the namespace that contains the declaration; otherwise, except as a friend declaration, the identifier is declared in the smallest namespace or block scope that contains the declaration. [ Note: These rules also apply within templates. — end note ] [ Note: Other forms of elaborated-type-specifier do not declare a new name, and therefore must refer to an existing type-name. See 3.4.4 and 7.1.6.3. — end note ]

  1. you are not creating a variable of an anonymous type
  2. you are not create a type

There is another example (in [basic.def]/2) from the standard that proves your example is not standard compliant :

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

Your example doesn't define anything (except an anonymous struct, who's fields can not be accessed).

Note an exception about the enum, because this case introduces two values to use.



来源:https://stackoverflow.com/questions/13138605/why-class-int-i-is-not-fully-standard-conformant

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!