考虑以下代码片段:
class A
{
int b[A::a]; //1, error
void foo(){ int b = A::a; } //2, ok
static const int a = 5;
}
Run Code Online (Sandbox Code Playgroud)
第 3.4.3.1/1 条(限定名称查找,类成员)说:
如果限定 id 的嵌套名称说明符指定一个类,则在类的范围内查找在嵌套名称说明符之后指定的名称(10.2)
这意味着将在类作用域中查找ain//1和 in 中的嵌套名称说明符之后的名称//2。
第 10.2 条(会员姓名查询)说:
10.2/2
以下步骤定义了类作用域 C 中成员名称 f 的名称查找结果。
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;
}
Run Code Online (Sandbox Code Playgroud)
这是因为第 3.4.1/7 和 3.4.1/8 节(非限定名称查找)中描述的行为。
该错误是因为int b[A::a];正在处理时,A还没有符号a。在编译时,仍然不完整,因为我们还没有达到类定义的A结束。}编译器不会“向前看”以查看源代码的未来行是否包含a.
您可以通过颠倒行的顺序来看到这一点:
class A
{
static const int a = 5;
int b[A::a]; // OK
};
Run Code Online (Sandbox Code Playgroud)
函数定义不存在同样的问题,因为内联函数体直到类定义编译之后才被编译。(抱歉,我没有方便的标准参考资料)