已知:
对于在模板的定义中所使用的非待决名,当检查该模板的定义时将进行无限定的名字查找。在这个位置与声明之间的绑定并不会受到在实例化点可见的声明的影响。 而对于在模板定义中所使用的待决名,它的查找会推迟到得知它的模板实参之时。 此时,ADL 将同时在模板的定义语境和在模板的实例化语境中检查可见的具有外部连接的(C++11 前)函数声明,而非 ADL 的查找只会检查在模板的定义语境中可见的具有外部连接的(C++11 前)函数声明。 (换句话说,在模板定义之后添加新的函数声明,除非通过 ADL 否则仍是不可见的。) 如果在 ADL 查找所检查的命名空间中,在某个别的翻译单元中声明了一个具有外部连接的更好的匹配声明,或者如果当同样检查这些翻译单元时其查找会导致歧义,那么行为未定义。 无论哪种情况,如果某个基类取决于某个模板形参,那么无限定名字查找不会检查它的作用域(在定义点和实例化点都不会)。
这里的最后一句话比较迷惑:无论哪种情况,如果某个基类取决于某个模板形参,那么无限定名字查找不会检查它的作用域(在定义点和实例化点都不会)。
因为 this->f()
也是无限定的。但这里确实查找到了基类的 f()
函数。对此 mq 白 给出的解释是:因为 f
是待决名,查找会推迟到得知它模板实参之时,此时父类不再取决于模板形参,已经实例化了,就没有上面说的那个问题了。
因此:
t()
中的 this->f()
是无限定的待决调用,会在明确它的模板实参之时再次进行关于 f
的名字查找,并且会查找基类,因此找到了基类的成员函数 f()
。
t2()
中的 f()
是无限定的非待决调用,检查该模板的定义时将进行关于 f
的无限定的名字查找(无法查找父类的定义),按照正常的查看顺序,先类内(查找不到),然后全局(找到)。