为何从模板基类继承的成员函数会提示未声明、编译报错?
问题解答
1. 编译错误的根本原因
你对koo是依赖名的判断是正确的,但这个报错的核心是C++模板的两阶段查找规则和依赖基类的查找限制:
- 第一阶段:处理模板定义阶段(还未代入具体模板参数),此时只会对非依赖名(不依赖模板参数的名字)进行查找;对于依赖名,只会做语法检查,完整的查找过程推迟到第二阶段。注意:这个阶段编译器不会在依赖基类(也就是依赖模板参数的基类,这里是
A<T>)的作用域中搜索任何名字,因为模板可能针对某些特定的T做偏特化,特化后的A<T>完全可以没有koo这个成员,编译器在第一阶段无法确定koo是否存在,所以默认不会去依赖基类查找未限定的名字。 - 第二阶段:模板实例化阶段(代入了具体模板参数),此时才会对依赖名进行查找,但非限定的名字依然不会主动到依赖基类中搜索。
至于ADL不生效的原因:ADL(实参依赖查找)的作用是根据函数实参的类型,到对应类型的关联命名空间中查找普通函数(非类成员函数)。首先你的koo是类的成员函数,本来就不在ADL的查找范围内;其次你这里实例化时T是int,int属于基础类型,没有关联的命名空间,ADL根本找不到任何符合要求的函数,自然就会报错。
你用this->koo(i)或者A<T>::koo(i)的本质是显式告诉编译器,这个名字是当前类的成员/来自基类A<T>,编译器就会明确将这个名字的查找范围指向类作用域,到实例化阶段就会到基类中查找对应成员,就不会报错了。
2. 两种场景报错信息不同的原因
两种场景下编译器的处理逻辑不同:
- 调用
koo(i)时:编译器知道你继承了依赖基类A<T>,且基类中存在koo这个成员名(虽然第一阶段不会去依赖基类查找,但编译器能识别到存在同名的候选符号),所以报错时会提示你“依赖基类的声明不会被非限定查找找到”,同时因为你写的是函数调用,编译器尝试过ADL查找也失败了,所以会附带ADL相关的提示。 - 调用
goo(i)时:整个代码中不存在任何和goo相关的声明,连基类里也没有这个名字,编译器找不到任何可能的关联候选,只会直接报名字未声明,最多提示你是不是拼写错误把koo写成了goo,自然不会提到ADL和依赖基类相关的内容。
内容的提问来源于stack exchange,提问作者Neymar87
相关产品推荐
相关产品推荐

