C++限定名查找为何允许重复类名却不支持重复命名空间名?
编译现象复现
以下代码存在两种完全不同的编译结果:
struct A { static void foo() {} }; namespace B { void bar() {} } void run() { // 可以正常编译通过 A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::A::foo(); // 触发编译错误 B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::B::bar(); }
对应C++限定名查找规则
两种写法的差异来源于类和命名空间的作用域名字注入规则完全不同:
- 类/结构体存在隐式的注入类名机制:C++标准明确规定,类定义完成后,编译器会自动在该类的作用域内插入一个与类同名的名字,这个名字直接指代当前类类型本身。我们平时在类A的成员函数内部直接写
A obj;就能声明A类型的对象,不需要额外加全局作用域限定,靠的就是这个隐式规则。
多层A::A的查找过程是逐层递进的:- 第一层在全局作用域查找
A,命中全局定义的结构体A - 进入A的作用域查找下一个
A,命中A自身隐式注入的类名,仍然指代结构体A - 后续每一层
::A的查找都会重复第二步的逻辑,无论叠加多少层,最终都会定位到结构体A的作用域,自然可以找到其中的静态成员函数foo,整个查找过程完全合法。
- 第一层在全局作用域查找
- 命名空间不存在同类隐式名字注入机制:多层
B::B的查找在第二层就会失败:- 第一层在全局作用域查找
B,命中全局定义的命名空间B - 进入B的作用域查找下一个
B时,命名空间B内部没有手动定义任何名为B的实体(既没有同名嵌套命名空间,也没有类、函数、变量等同名声明),名字查找直接失败,触发编译错误。
- 第一层在全局作用域查找
补充验证:如果手动在命名空间B内声明同名嵌套实体,比如写
namespace B { inline namespace B {} },那么B::B的写法也会合法,但这是手动声明的结果,不是编译器默认提供的规则。
内容的提问来源于stack exchange,提问作者andnowwhat
相关产品推荐
相关产品推荐

