C++ 嵌套枚举和嵌套类具有不同的行为

C++ 嵌套枚举和嵌套类具有不同的行为,c++,C++,考虑以下两个例子: 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 }; 标准中是否有一部分解释了这种行为 [C++11:7.2/10]:在立即包含枚举说明符的作用域中声明每个枚

考虑以下两个例子:

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
};
标准中是否有一部分解释了这种行为

[C++11:7.2/10]:
在立即包含枚举说明符的作用域中声明每个枚举名称和每个非作用域枚举数。[……]


不存在类规则。

< P>是的,C++标准中有这样的部分。

第一个是

9.9嵌套类型名称

1类型名称遵守与其他名称完全相同的范围规则。在里面 特别是,在类定义中定义的类型名不能为 未经资格认证就在其课堂外使用

更确切地说,可以引用下面的引语

2类成员的名称只能按以下方式使用:-在 其类别(如上所述)或衍生类别(第10条)的范围 从它的类-在之后。运算符应用于 其类的类型(5.2.5)或从其类派生的类,-之后 应用于指向其类(5.2.5)对象的指针的->运算符 或从其类派生的类,在::scope解析之后 运算符(5.1)应用于其类或派生类的名称 从它的班级

第二个是

11.7嵌套类

1嵌套类是成员,因此具有与相同的访问权限 任何其他成员。封闭类的成员没有特殊的 访问嵌套类的成员通常的访问规则(第11条) 应遵守

在本定义中,如果不考虑打字错误(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至圣安塔里奥。我不理解这一点扎沃霍兹

所以我会尝试调查的方法。如果我们修复了你电脑中不相关的错误 示例
struct X

  • 缺少
    16之后
  • 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嵌套类中的一段标准 他大概想让你从中了解到筑巢与你的生活无关 令人费解的事但是编译器在限定名
X::z
并且不会吐出限定名
Y::z
使其看起来像 struct
E
在struct
X
中的嵌套对于 结构
Y
中的枚举
E

回想一下,对于在范围
S
中声明的任何名称
N
限定
S::N
S
范围内是多余的,就像 限定
::N
在全局范围内对于全局名称
N
是多余的

如果在
X
[
Y
]的范围内声明了
z
,则在
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
                 
没有任何变化

因此,筑巢确实与谜题无关。事实是 结构类成员在结构类作用域中声明,而不是 在封闭范围中,和普通旧枚举的枚举数在 封闭范围。轨道上的轻量级比赛为你提供了标准参考 对于后一个事实

这还让你感到惊讶吗?你不会感到惊讶的是:

struct E { static const int z = 16; };
static const int b = z;
    
enum E1 { z = 16 };
static const int b = z;
不在与
b
相同的范围内声明
z
。因此,您可能会感到惊讶:

struct E { static const int z = 16; };
static const int b = z;
    
enum E1 { z = 16 };
static const int b = z;
是否将
z
声明在与
b
相同的范围内?好吧,这就是普通老枚举的方式 一直以来,因为C++继承了它们和C。这很大程度上是什么造成的。 他们是普通的老伯爵

在C++11中,普通旧枚举的这一特性就是 行话来说,普通的旧枚举称为无范围枚举。而这一特点 以及无范围的enumera的准备情况