这是一个后续问题。
在previous question中,@ JohannesSchaub-litb表示以下代码不完全符合标准:
class { int i; }; //unnamed-class definition. § 9/1 allows this!
然后他补充道,
虽然它在语法上是有效的,但它打破了这样一个规则,即这样的类必须在其封闭范围内声明至少一个名称。
我真的不明白这一点。他在说什么名字?
有没有人可以进一步详细说明(最好引用标准)?
答案 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。 - 结束说明]
标准中还有另一个示例(在[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
您的示例未定义任何内容(匿名结构除外,无法访问其字段)。
请注意有关枚举的例外情况,因为这种情况会引入两个要使用的值。