为什么要上课{int i; };是不是完全符合标准?

时间:2012-10-30 12:05:08

标签: c++ class definition identifier standards-compliance

这是一个后续问题。

previous question中,@ JohannesSchaub-litb表示以下代码完全符合标准:

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

然后他补充道,

  

虽然它在语法上是有效的,但它打破了这样一个规则,即这样的类必须在其封闭范围内声明至少一个名称。

我真的不明白这一点。他在说什么名字?

有没有人可以进一步详细说明(最好引用标准)?

5 个答案:

答案 0 :(得分:51)

该标准的第9条允许class {public: int i;}(注意缺少最后的分号),因为未命名的类的 decl-specifier-seq 可能会用于其他一些构造,例如:一个typedef或一个变量声明。 class {public: int i;};的问题(注意最后的分号现在存在)是这个类规范现在变成了一个声明。根据该标准第7条第3款,这是非法声明:

  

在这种情况下,除了声明未命名的位字段(9.6)之外, decl-specifier-seq 应在程序中引入一个或多个名称,或者重新声明名称由先前的声明引入。

答案 1 :(得分:26)

关键在于,通过声明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我永远不会打电话......
  • 算了吧! (};

如果从程序中删除该声明,则不会发生任何变化。

答案 2 :(得分:11)

class { int i; };不是有效的声明,因为它是简单声明而没有 init-declarator-list 但它没有引入(或重新声明) -declare)一个班级名称。

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

  

简单声明中,只有在声明类(第9节)或枚举(7.2)时,才能省略可选的 init-declarator-list ,即,当 decl-specifier-seq 包含类说明符时, elaboratedtype-specifier 包含 class-key (9.1),或枚举说明符。在这些情况下,当 decl-specifier-seq 中存在类说明符枚举说明符时,这些说明符中的标识符为声明声明的名称之间(作为类名枚举名称枚举器,具体取决于语法)。 在这种情况下,除了声明未命名的位字段(9.6)之外, decl-specifier-seq 应在程序中引入一个或多个名称,或者重新声明名称由先前的声明引入。

答案 3 :(得分:10)

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; } abstract-declarator (标准,§8),但不是有效的声明(§7)。这是@ JohannesSchaub-litb引用的规则:对于有效的声明,您需要声明一些内容,例如:类名或变量名。

答案 4 :(得分:3)

你打破了[basic.scope.pdecl]/6,其中说:

  

首先在详细说明类型中声明的类的声明点如下:
   - 表格形式的声明
      class-key attribute-specifier-seqopt identifier ;

     

标识符在包含声明的范围内声明为类名,否则为
   - 对于形式的详细类型说明符
     class-key identifier

     

如果在的decl-specifier-seq或parameter-declaration-clause中使用了elaborated-type-specifier。   在命名空间范围内定义的函数,标识符在命名空间中声明为类名   包含声明;否则,除了作为朋友声明之外,标识符在声明中声明   包含声明的最小命名空间或块范围。 [注意:这些规则也适用于   模板。 - 尾注] [注:其他形式的详细类型说明符不声明新名称,   因此必须引用现有的类型名称。见3.4.4和7.1.6.3。 - 结束说明]

  1. 您没有创建匿名类型的变量
  2. 您没有创建类型
  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
    

    您的示例未定义任何内容(匿名结构除外,无法访问其字段)。

    请注意有关枚举的例外情况,因为这种情况会引入两个要使用的值。