43

这是一个后续问题。

在上一个问题中,@JohannesSchaub-litb 说以下代码完全符合标准:

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

然后他补充说,

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

我真的无法理解这一点。他在说什么名字?

谁能进一步详细说明(最好引用标准)?

4

5 回答 5

51

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

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

于 2012-10-30T12:50:49.347 回答
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我永远不会打电话给...
  • 忘了它!( };)

如果你从你的程序中删除那个声明,什么都不会改变。

于 2012-10-30T12:22:42.173 回答
11

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

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

simple-declaration中,可选的init-declarator-list只有在声明类(第 9 条)或枚举(7.2)时才能省略,也就是说,当decl-specifier-seq包含class-specifierexplaindtype时-带有类键(9.1) 或enum-specifier 的说明符。在这些情况下,只要在decl-specifier-seq中存在类说明符枚举说明符,这些说明符中的标识符就在声明所声明的名称中(如class-namesenum-namesenumerators,取决于语法)。在这种情况下,除了未命名位域(9.6)的声明外,decl-specifier-seq应在程序中引入一个或多个名称,或应重新声明由先前声明引入的名称。

于 2012-10-30T12:52:28.500 回答
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; }是一个抽象声明符(标准,§8),但不是一个有效的声明(§7)。这就是@JohannesSchaub-litb 引用的规则:对于有效的声明,您需要声明一些东西,例如类名或变量名。

于 2012-10-30T12:28:35.963 回答
3

你打破了[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

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

注意枚举的一个例外,因为这种情况引入了两个要使用的值。

于 2012-10-30T12:56:28.627 回答