类成员限定名称查找

时间:2014-06-19 06:20:25

标签: c++ class language-lawyer

请考虑以下代码段:

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(非限定名称查找)一节中描述的行为。

2 个答案:

答案 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:

  

在声明类成员之后,可以在其类的范围内查找成员名称。 [...]

通过暗示,在该类成员声明之前,该成员名称​​不能在该类的范围内被查找