为何编译器可正确推导类作用域内类型的模板参数T?
问题解析:模板参数推导与作用域的关系
先看这段可正常编译的代码:
template <typename T> void call(T in){} struct test{ using type_t = int; void f() { type_t a = 1; call(a); } }; int main(){ test t; t.f(); return 0; }
问题
type_t仅在struct test的作用域内可用,为何编译器能将模板函数call的参数T正确推导为type_t?而若将call改为如下非模板函数:
void call(type_t in){}
则会出现预期的错误提示:'type_t' was not declared in this scope。
核心差异解析
模板函数的参数推导逻辑
当在test::f()里调用call(a)时,编译器是先拿实参a的类型倒推模板参数T。a的类型是test::type_t(也就是int),这个类型在test的作用域里是明确的。推导完成后,编译器会实例化出具体的函数call<int>(int in)——这个实例化后的函数里根本不会出现type_t这个名字,自然不存在作用域找不到的问题。
非模板函数的声明规则
非模板函数void call(type_t in)的声明直接用到了type_t,但这个类型别名只在test的内部作用域有效。编译器处理全局作用域下的这个函数声明时,必须当场解析type_t是什么,但此时它不在test的作用域里,找不到这个类型名的定义,所以直接抛出作用域错误。
一句话总结:模板函数是“看实参定类型”,实参类型在调用点能找到就行;非模板函数是“声明时就得把参数类型搞清楚”,声明所在的作用域找不到类型名就报错。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

