在下面的代码段中,我可以理解(来自§3.3.2/ 6第二个要点)声明B
中的名称struct B* p;
作为类注入到全局命名空间中-name
struct A {
// struct B{};
int B;
struct B* p;
};
void f(B&) {}
int main()
{
A a;
f(*a.p);
}
§3.3.2/ 6:
声明一个类第一个的声明 elaborated-type-specifier 如下:
表格
的声明class-key attribute-specifier-seq opt 标识符;
标识符在范围内被声明为类名 包含声明,否则
表格的详细说明类型
class-key 标识符
如果在定义的函数的 decl-specifier-seq 或 parameter-declaration-clause 中使用 elaborated-type-specifier 在命名空间作用域中,标识符被声明为a 包含声明的命名空间中的 class-name ;否则,除 friend 声明外,标识符是 在包含的最小命名空间或块范围中声明 宣言。 [注意:这些规则也适用于模板。 - 结束 注意] [注意: elaborated-type-specifier 的其他形式不 声明一个新名称,因此必须引用现有的类型名称。 见3.4.4和7.1.6.3。 - 结束记录]
但是,如果我取消注释struct B{};
内struct A
的定义,我之前所说的关于将名称B
注入全局命名空间的内容,就不再发生了,因为代码无法编译。我认为这与上面的第一个(强调我的)一词有关,因为现在 class-name B
,在声明struct B* p;
中不再是它在声明区域中的第一个声明 。我说对了吗?
假设我的解释是正确的,为什么在这种情况下 class-name B
没有注入全局命名空间?请注意,在这种情况下,嵌套类struct B{};
将隐藏在A中,即,即使我们将函数f
的声明更改为void f(A::B&)
,代码也无法编译。
还有一点我不清楚:是什么让实现者决定在第二个项目符号点中将类名注入到命名空间或块范围内,包含详细类型说明符以上?也就是说,为什么他们不将类名声明留在类范围内?
答案 0 :(得分:2)
你是对的,§3.3.2/ 6中的 first 关键字也是以下原因:
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仅在没有找到先前声明的情况下执行
如果class-key引入了elaborated-type-specifier 此查找找不到先前声明的类型名称,或者如果找到 elaborated-type-specifier出现在声明中,格式为:
class-key attribute-specifier-seqopt identifier;
elaborated-type-specifier是一个引入的声明 class-name,见3.3.2.the
最后我追踪这个行为可能是C99的继承6.7.2.3/p8
如果是表单的类型说明符
struct-or-union identifier
发生 除了作为上述表格之一的一部分外,没有其他声明 标识符作为标记是可见的,然后它声明不完整 结构或联合类型,并将标识符声明为标记 那种类型.113)
113)不存在与枚举类似的构造。
答案 1 :(得分:0)
我会说你的解释是正确的。取消注释struct B{};
后,struct B* p;
行只会引用该结构A::B
。
要回答您的问题,为什么当您将struct B {};
注释掉时,名称struct B
会插入到全局范围内。我会这么说,因为作者并不希望你(有些)默默地声明B
成为A
的成员而不使用成员规范名称为B
。