调用C++模板函数输出不符合预期:为何结果是TS而非SS?
为什么代码输出是TS而不是SS?
先把你的代码贴出来方便分析:
#include <iostream> template<typename T> void foo(T) { std::cout << "T" << std::endl;; } struct S { }; template<typename T> void call_foo(T t) { foo(S()); foo(t); } void foo(S) { std::cout << "S" << std::endl; } int main() { call_foo(S()); }
咱们一步步拆解问题的核心——模板函数的两阶段名字查找规则,这是你预期和实际输出不符的关键:
foo(S())的调用逻辑:
在模板call_foo的定义里,foo(S())的参数是S(),这是一个不依赖模板参数T的表达式。对于这种非依赖的名字,编译器会在模板定义的位置进行查找,而不是等到模板实例化的时候。
看代码顺序:call_foo模板定义在void foo(S)这个非模板函数的前面,所以当编译器处理call_foo里的foo(S())时,它只能看到前面那个模板版本的foo<T>,因此这里会调用模板foo<T>,输出"T"。foo(t)的调用逻辑:
而foo(t)里的t是模板参数T的实例,属于依赖模板参数的名字。对于这种名字,编译器会进行两阶段查找:- 第一阶段:在模板定义位置查找非依赖的候选;
- 第二阶段:在模板实例化的位置(也就是
main函数调用call_foo(S())的时候),查找依赖于参数类型的候选,包括参数依赖查找(ADL)。
此时,void foo(S)已经被声明了,编译器会优先匹配这个更具体的非模板函数,输出"S"。
两者结合起来,最终输出就是TS。
如果想要让foo(S())也调用非模板的foo(S),你只需要在call_foo模板定义之前提前声明void foo(S)即可,修改后的代码如下:
#include <iostream> template<typename T> void foo(T) { std::cout << "T" << std::endl;; } struct S { }; void foo(S); // 提前声明非模板函数 template<typename T> void call_foo(T t) { foo(S()); foo(t); } void foo(S) { std::cout << "S" << std::endl; } int main() { call_foo(S()); }
这样修改后,输出就会是你预期的SS了。
内容的提问来源于stack exchange,提问作者BlahGuy
相关产品推荐
相关产品推荐

