考虑以下两个例子:
struct X
{
class E { static const int z = 16 };
static const int b = X::z; // X has no member z
};
struct Y
{
enum E { z = 16 };
static const int b = Y::z; // OK
};
是否有标准的一部分解释了这种行为?
答案 0 :(得分:5)
是的,C ++标准中有这样的部分。
第一个是
9.9嵌套类型名称
1类型名称遵循与其他名称完全相同的范围规则。在 特别是,类定义中定义的类型名称不能 在没有资格的情况下在课外使用。
更准确地说引用以下引用
2类成员的名称只能按如下方式使用: - 在 同类的范围(如上所述)或派生的类别(第10条) 从它的班级, - 之后。运算符应用于表达式 它的类的类型(5.2.5)或从它的类派生的类, - 之后 - >运算符应用于指向其类对象的指针(5.2.5) 或者从类中派生的类, - 在:: scope解析之后 operator(5.1)应用于其类的名称或派生的类 从班上来。
,第二个是
11.7嵌套类
1嵌套类是成员,因此具有相同的访问权限 任何其他成员。附上课程的成员没有特别之处 访问嵌套类的成员; 通常的访问规则(第11条) 应遵守。
在此定义中,如果不考虑拼写错误(z定义后没有分号)
struct X
{
class E { static const int z = 16 };
static const int b = X::z; // X has no member z
};
您正在尝试访问z 1)而没有资格,2)具有私有访问控制。
正确的定义可能看起来像
struct X
{
class E { public: static const int z = 16; };
static const int b = E::z;
};
对于枚举,未被覆盖的枚举的枚举器是定义枚举的类的成员。
9.2班级成员
1类定义中的成员规范声明了完整集 班级成员;其他任何成员都无法添加。的成员 类是数据成员,成员函数(9.3),嵌套类型和 的枚举强>
答案 1 :(得分:3)
[C++11: 7.2/10]:
每个 enum-name 和每个 unscoped 枚举器都在包含 enum-specifier 的范围内声明。 [..]
类没有这样的规则。
答案 2 :(得分:0)
您要求引用标准,并且您已找到正确的引文,但似乎它们没有帮助:
这是如何暗示可以从外部声明区域访问枚举成员? - St.Antario
+1到St.Antario。我不明白。 - zavhoz
所以我会尝试调查方法。如果我们修复你的无关错误
示例struct X
:
;
。E::z
是私有的。我们有:
struct X
{
struct E { static const int z = 16; };
static const int b = X::z;
};
编译你的代码如此修复,clang 3.4抱怨:
error: no member named 'z' in 'X'; did you mean 'E::z'?
static const int b = X::z;
^~~~
E::z
(gcc 4.9.0和VC ++ 2013在同一行提供错误,但帮助较少 诊断)
然而,没有关于Y::z
的此类抱怨。教训似乎是:
类定义不声明封闭中的类成员 范围。
普通的枚举定义 声明了枚举器 封闭范围。
我在这里说普通的枚举,因为从C ++ 11开始,我们也有了一位新的爱好者
有点枚举,但Y::E
是一个普通的老词。
如果这是教训,它似乎没有任何特别之处 与嵌套有关。
来自莫斯科的Vlad已经从 11.7嵌套课程中引用了标准段落
他可能希望你收集那些筑巢与你的无关
难题。但是编译器barf在限定名称X::z
的事实
并且没有限定名称Y::z
的barf使它看起来像
在结构E
中嵌套 struct X
具有一定的嵌套性
结构E
中的枚举 Y
没有。
回想一下,对于在范围N
中声明的任何名称S
,
S::N
范围内的S
冗余,就像::N
一样
对于全局名称N
,资格z
在全局范围内是多余的。
如果在X
[Y
]的范围内声明了X
,则属于
Y
[z
]您可以将其称为struct X
{
struct E { static const int z = 16; };
static const int b = z;
};
struct Y
{
enum E { z = 16 };
static const int b = z;
};
。所以,让我们删除多余的东西
示例代码中的资格:
error: use of undeclared identifier 'z'; did you mean 'E::z'?
static const int b = z;
^
E::z
现在看看铿锵有什么:
X
Y
中存在同样的问题;在X
中仍然没有问题。但是由于
我们已经摆脱了多余的资格,Y
根本没有被提及。
X
从未被提及。所以也许现在它看起来不再那样了
嵌套与谜题有关。
接下来让我们继续前进,摆脱Y
和struct E { static const int z = 16; };
static const int b = z;
enum E1 { z = 16 };
static const int b = z;
int main()
{
return 0;
}
。这是程序:
error: use of undeclared identifier 'z'; did you mean 'E::z'?
static const int b = z;
^
E::z
并且clang说:
struct E { static const int z = 16; };
static const int b = z;
完全没有变化。
因此,嵌套确实与谜题毫无关系。事情的事实是 struct | class成员在struct | class作用域中声明,不是 在封闭范围内,普通旧枚举的枚举器在声明中声明 封闭范围。 Orbit中的Lightness Races为您提供了标准参考 对于后一事实。
这仍然让你感到惊讶吗?很难让你感到惊讶:
z
未在与b
相同的范围内声明enum E1 { z = 16 };
static const int b = z;
。所以可能让你大吃一惊:
z
在与b
相同的范围内声明int
?好吧,那就是简单的老枚举
一直以来,因为C ++继承了它们和C.这主要是因为它
他们普通的枚举。
在C ++ 11中,普通旧枚举的范围提升特性是其原因
行话,普通的旧枚举称为 unscoped enums 。而这个特点就像
以及未见范围的调查员对enum struct SE : short {
z = 16
};
//const int b = z; <- Undeclared identifier
//const short b = SE::z; <- No implicit conversion
SE b = SE::z; //OK
const int c = static_cast<int>(SE::z); //OK
衰变的准备情况
使用无范围的枚举长期成为C ++中不舒服的根源。
因此,在C ++ 11中,我们现在有一个更严格的替代方案,称为范围的枚举或 枚举类,它是这样的:
{{1}}
看起来scoped enums对于范围界定不会让你感到惊讶 他们的普查员,但会通过抵制隐含而使你感到惊讶 积分转换。