C++省略命名空间时如何选择?为何Bar中最后一个A来自ns1而非ns2?
C++命名空间查找与模板类型解析问题解答
问题1:省略命名空间时,C++如何选择对应的命名空间?
C++的名字查找遵循从"近"到"远"的优先级规则:
- 优先在当前作用域(比如函数内部、类内部)查找,包括嵌套的内层作用域;
- 当前作用域找不到时,去包含当前作用域的命名空间里查找,比如在
ns2的类中先找ns2命名空间内的名字; - 仍找不到的话,继续往外层命名空间(比如全局命名空间)查找;
- 针对模板相关的函数调用,还有**实参依赖查找(ADL)**规则:编译器会额外去函数实参所在的命名空间里查找匹配的函数,但类/模板类的名字不会触发ADL;
- 如果代码里有
using声明(如using ns1::A;)或using指令(如using namespace ns1;),会把指定命名空间的名字引入当前作用域,优先级高于外层命名空间的查找。
问题2:为何ns2::B的Bar类型中最后一个A来自ns1命名空间?
先明确代码里的核心差异:
ns1中的A是模板类:template <typename T, typename U> struct A {};ns2中的A是普通结构体:struct A : ns1::A<int, A> {};
在ns2::B的Bar定义typedef ns1::A<A, B> Bar;里,我们写的A后面跟着<>,说明它需要是一个模板名,此时的名字查找逻辑如下:
- 先查找
ns2::B自身的成员,没有匹配的模板A; - 接着查找
B的直接基类ns1::A<ns2::A, B>的作用域:模板类的注入类名(injected-class-name)会自动成为基类作用域的一部分,这里基类ns1::A<...>的注入类名就是A,并且它是可直接作为模板使用的名字(对应ns1::A模板); - 虽然
ns2命名空间里有A,但它是普通结构体,无法满足<>的模板使用要求,因此编译器会选择基类作用域里的模板A(即ns1::A)。
最终,ns1::A<A, B>被解析为ns1::A<ns1::A<ns2::A, ns2::B>, ns2::B>,也就是你看到的结果。
内容的提问来源于stack exchange,提问作者Pootis Spencer
相关产品推荐
相关产品推荐

