请考虑以下代码段:
class A
{
int b[A::a]; //1, error
void foo(){ int b = A::a; } //2, ok
static const int a = 5;
}
条款3.4.3.1/1(合格名称查询,班级成员)说:
如果qualified-id的嵌套名称说明符指定了一个类,那么 在查找嵌套名称说明符后指定的名称 类的范围(10.2)
这意味着在a
和//1
中的嵌套名称说明符之后的名称//2
将在类范围中查找。
第10.2条(会员名称查询)说:
10.2 / 2
以下步骤定义成员名称的名称查找结果 f在类范围C中。
10.2 / 3
C中f的查找集,称为S(f,C)...
S(f,C)计算如下:
10.2 / 4
如果C包含名称f的声明,则声明集 包含在C中声明的满足f的每个声明 查找发生的语言结构的要求。
我不清楚以下内容:
我引用的引文暗示,对于//1
和//2
,都应使用相同的成员查找规则。 但实际上它有所不同。为什么我的推理错了?
注意 :我知道类范围内的非限定名称查找规则。我在下面的代码片段中理解了这种行为:
class A
{
int b[a]; //error
void foo(){ int b = a; } //ok
static const int a = 5;
}
这是因为3.4.1 / 7和3.4.1 / 8(非限定名称查找)一节中描述的行为。
答案 0 :(得分:4)
错误是因为在处理int b[A::a];
时,A
还没有符号a
。在编译时,A
仍然不完整,因为我们尚未达到类定义的结束}
。编译器没有“向前看”以查看未来的源代码行是否包含a
的定义。
您可以通过颠倒行的顺序来看到这一点:
class A
{
static const int a = 5;
int b[A::a]; // OK
};
函数定义没有相同的问题,因为直到编译类定义之后才编译内联函数体。 (对不起,我没有方便的标准参考资料)
答案 1 :(得分:3)
成员声明int b[A::a];
不在A::a
(3.3.7p1)的潜在范围中,而void A::foo()
的正文在潜在范围内(3.3.7p1b1):
1)在类中声明的名称的潜在范围不仅包括名称声明后面的声明区域,还包括所有函数体, brace-or-equal-initializers 非静态数据成员,以及该类中的默认参数(包括嵌套类中的这些内容)。
3.4.3.1p1引用了注释中的潜在范围规则:
[...] [注意:可以在潜在范围(3.3.7)的任何一点使用qualified-id引用类成员。 - 结束记录] [...]
当然,注释是非规范性的,因此结论必须是标准中其他材料隐含的潜在范围规则。我相信这个其他材料具体是3.3.2p5:
在声明类成员之后,可以在其类的范围内查找成员名称。 [...]
通过暗示,在该类成员声明之前,该成员名称不能在该类的范围内被查找
。