【问题标题】:Class member qualified name lookup类成员限定名查找
【发布时间】:2023-04-07 03:49:01
【问题描述】:

考虑以下代码sn-p:

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 条(合格名称查找,类成员)说:

如果限定 ID 的嵌套名称说明符指定了一个类,则 在嵌套名称说明符之后指定的名称在 类的范围(10.2)

这意味着在 //1//2 中嵌套名称说明符之后的名称 a 将在类范围内查找。

第 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 应应用相同的成员查找规则。 但实际上它是不同的。为什么我的推理是错误的?

注意:我知道类范围内的非限定名称查找规则。我在以下代码 sn-p 中理解了这种行为:

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

【问题讨论】:

标签: c++ class language-lawyer


【解决方案1】:

错误是因为在处理int b[A::a]; 时,A 还没有符号a。在编译时,A 仍然不完整,因为我们还没有达到类定义的结束 }。编译器不会“向前看”来查看未来的源代码行是否包含a 的定义。

你可以通过颠倒行的顺序来看到这一点:

class A
{
    static const int a = 5;
    int b[A::a]; // OK
};

函数定义没有同样的问题,因为内联函数体直到类定义编译之后才被编译。 (抱歉,我没有方便的标准参考)

【讨论】:

  • 是否存在合适的标准参考?
【解决方案2】:

成员声明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) 中的任何点使用限定 ID 来引用类成员。 —结束注释] [...]

当然,注释是非规范性的,因此结论必须是标准中的其他材料隐含了潜在的范围规则。我相信这个其他材料具体是 3.3.2p5:

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

暗示,在声明该类成员之前,该成员名称​​无法在该类的范围内查找。

【讨论】:

  • 感谢您的回答。但是您能否澄清以下几点:在其潜在范围内的任何点都可以使用限定 ID 来引用类成员这一事实并不意味着 不能在其潜在范围之外引用该类成员。而且这不是真的。实际上,使用qualified-id,我们可以在其范围之外使用类成员。应用我假设范围推理在我的情况下是不正确的。也许我没听懂你的意思?
  • @DmitryFucintv 使用限定 ID,您可以访问其范围之外的类成员,但您不能访问其 潜在 范围之外的该类成员。请注意,除了类中的函数体等之外,潜在范围还包括声明点之后翻译单元的全部剩余部分。
  • @DmitryFucintv 再次,注意3.3.2p5注释中的示例;这说明在没有该段落的情况下,根本无法在其类的范围内查找该成员。
猜你喜欢
  • 2014-08-05
  • 2016-05-22
  • 2015-03-18
  • 1970-01-01
  • 1970-01-01
  • 2021-06-17
  • 2013-11-04
  • 2013-02-22
  • 2013-10-24
相关资源
最近更新 更多