为何该C++代码示例中的名字查找行为看起来存在不一致?
问题背后的C++名字查找规则解析
首先给出你提到的可复现问题的代码:
template <typename Type, typename T> class zz { }; class foo { template <typename T> using zz = ::zz<foo, T>; struct own_type : zz<double> { own_type(): zz<foo, double>{} {} // 移除foo参数编译失败 }; template <typename T> struct zz_type_gen : zz<T> { zz_type_gen(): zz<T>() {} }; zz<int> _oi; zz_type_gen<char> _od; };
你观察到的差异本质是C++标准明确规定的非模板类名字查找规则和模板两阶段名字查找规则的区别,不存在规则不一致的问题,具体拆解如下:
1. 非模板嵌套类own_type的查找逻辑
非模板类的名字查找没有延迟阶段,会在语法解析时直接在当前作用域链完成查找:
own_type的基类声明zz<double>中的zz查找时优先匹配到foo内的别名模板,展开为::zz<foo, double>,所以继承逻辑是合法的。- 进入
own_type作用域后,基类::zz<foo, double>的注入类名会被引入到own_type的作用域:也就是在own_type内部,未限定的zz会优先指向全局的双参数模板::zz,而非foo内的单参数别名模板。 - 因此构造函数初始化列表中如果写
zz<double>{},匹配到的是全局双参数::zz,仅传递一个double参数会报参数数量错误,必须补全两个参数写zz<foo, double>{},或者显式指定外层作用域的别名foo::zz<double>{}才能编译通过。
2. 模板嵌套类zz_type_gen的查找逻辑
模板存在两阶段查找规则,依赖名的查找会推迟到模板实例化阶段完成:
zz_type_gen是模板类,代码中zz<T>属于依赖名(后续模板参数T依赖当前模板的参数),第一阶段(模板定义时)不会对它做最终解析,只会检查基本语法合法性。- 当
zz_type_gen在foo作用域内被实例化时,才会对依赖名zz做查找,此时会优先匹配foo内定义的单参数别名模板zz,zz<T>展开后就是::zz<foo, T>,和基类的类型完全匹配,因此初始化列表写zz<T>()可以正常编译。
内容的提问来源于stack exchange,提问作者Joseph
相关产品推荐
相关产品推荐

