这是一个后续问题。
在上一个问题中,@JohannesSchaub-litb 说以下代码不完全符合标准:
class { int i; }; //unnamed-class definition. § 9/1 allows this!
然后他补充说,
虽然它在语法上是有效的,但它打破了这样的类必须在其封闭范围内声明至少一个名称的规则。
我真的无法理解这一点。他在说什么名字?
谁能进一步详细说明(最好引用标准)?
这是一个后续问题。
在上一个问题中,@JohannesSchaub-litb 说以下代码不完全符合标准:
class { int i; }; //unnamed-class definition. § 9/1 allows this!
然后他补充说,
虽然它在语法上是有效的,但它打破了这样的类必须在其封闭范围内声明至少一个名称的规则。
我真的无法理解这一点。他在说什么名字?
谁能进一步详细说明(最好引用标准)?
标准的第 9 条允许class {public: int i;}
(注意缺少最后的分号),因为未命名类的decl-specifier-seq可能用于其他一些构造,例如 typedef 或变量声明。(请注意,现在出现了最后的分号)的问题class {public: int i;};
是这个类规范现在变成了一个声明。这是标准第 7 条第 3 款的非法声明:
在这种情况下,除了未命名位域(9.6)的声明外,decl-specifier-seq应在程序中引入一个或多个名称,或应重新声明由先前声明引入的名称。
关键是,通过声明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
我永远不会打电话给...};
)如果你从你的程序中删除那个声明,什么都不会改变。
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-specifier、explaindtype时-带有类键(9.1) 或enum-specifier 的说明符。在这些情况下,只要在decl-specifier-seq中存在类说明符或枚举说明符,这些说明符中的标识符就在声明所声明的名称中(如class-names、enum-names或enumerators,取决于语法)。在这种情况下,除了未命名位域(9.6)的声明外,decl-specifier-seq应在程序中引入一个或多个名称,或应重新声明由先前声明引入的名称。
来自 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 引用的规则:对于有效的声明,您需要声明一些东西,例如类名或变量名。
你打破了[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。——尾注]
标准中的另一个示例(中[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
您的示例未定义任何内容(匿名结构除外,无法访问谁的字段)。
注意枚举的一个例外,因为这种情况引入了两个要使用的值。