我对§3.3.2/6中"第一"一词的解释是否正确?

Is my interpretation of the word 'first' in §3.3.2/6 correct?

本文关键字:解释 是否 第一 我对      更新时间:2023-10-16

在下面的片段中,我可以理解(从§3.3.2/6第二个要点)声明struct B* p;中的名称B作为类名注入全局命名空间。

struct A {
 //   struct B{};
    int B;
    struct B* p;
};
void f(B&) {}
int main()
{
    A a;
    f(*a.p);
}

§3.3.2/6:

类的声明点详细的类型说明符如下所示:

  • 对于形式的声明

    类键属性说明符seqopt标识符;

    标识符被声明为作用域中的类名包含声明,否则

  • 对于形式的详细说明的类型说明符

    类密钥标识符

    如果在命名空间范围中定义的函数的decl说明符seq参数声明子句中使用了详细说明的类型说明符,则标识符声明为包含声明的命名空间中的类名;否则,除了朋友声明外,标识符为在包含公告[注意:这些规则也适用于模板。--end注意][注意:其他形式的详细类型说明符不声明一个新名称,因此必须引用现有的类型名称。见3.4.4和7.1.6.3。——尾注]

然而,如果我在struct A中取消注释struct B{};的定义,那么我之前所说的关于将名称B注入全局命名空间的内容将不再发生,因为代码不会编译。我认为这与上面的单词first(强调我的)有关,因为现在类名B在声明struct B* p;中不再是其声明区域中的第一个声明。我这么说对吗?

假设我的解释是正确的,为什么在这种情况下,类名B没有注入全局命名空间?注意,在这种情况下,嵌套类struct B{};将隐藏在A中,即,即使我们将函数f的声明更改为void f(A::B&),代码也不会编译。

还有一点我不清楚:是什么让实现者决定在上面的第二个要点中,将类名注入到包含详细说明的类型说明符的命名空间或块范围中?也就是说,他们为什么不把类名声明留在类作用域内?

您是正确的,§3.3.2/6中的第一个关键字也是导致以下情况的原因:

struct A {
    struct B *p;
    struct B{};
    int b;
};
void f(B* arg) {
    std::cout << std::is_same<decltype(arg), A::B*>::value; // not the same type
}
int main()
{
    A a;
    f(a.p);
}

为什么在这种情况下,类名B没有被注入全局名称空间?

正如dyp所指出的,[basic.lookup.elab]/2解释了3.3.2只有在找不到以前的声明的情况下才执行

如果详细说明的类型说明符是由类键引入的,并且此查找找不到以前声明的类型名,或者如果详细的类型说明符出现在声明中,其形式为:

类密钥属性说明符seqopt标识符;

详细的类型说明符是一个声明,它引入3.3.2中描述的类名。

最后,我追踪到这种行为可能是C99 6.7.2.3/p8 的继承

如果形式的类型说明符

结构或联合标识符

发生除了作为上述表格的一部分,没有其他声明如果标识符作为标记可见,则它声明不完整结构或联合类型,并将标识符声明为113)

113)不存在具有enum的类似构造。

我认为你的解释是正确的。当您取消对struct B{};的注释时,struct B* p;行将简单地引用该结构体A::B

为了回答您的问题,当您将struct B {};注释掉时,名称struct B会插入全局范围。我想说的是,这是因为作者不希望您(在某种程度上)无声地将B声明为A的成员,而不使用成员规范作为名称B