函数模板:一个模板装任意类型

写一次,用多次:编译器按调用类型现场生成

商用

◎学完你会

1一个 max 模板,换着类型用

写一个 template<typename T> T myMax(T a, T b),选一种类型看编译器按它实例化出对应的函数。

template<typename T>
T myMax(T a, T b) { return a>b ? a : b; }
选一种类型,看模板被实例化成什么。
模板本身只是蓝图,不产生代码;每次用具体类型调用,编译器才现场实例化出该类型的函数。

2关键命令

写法含义
template<typename T>声明模板:T 是类型参数(占位符)
T myMax(T a, T b)模板函数:T 代表"调用时传入的类型"
myMax(3, 7)编译器按 int 实例化(也可显式 myMax<int>(3,7))
template<typename T, typename U>多类型参数模板
✅ typename 和 class 在此处可互换(template<class T> 等价)。模板让你写一次算法、适配无数类型,正是 STL 的基础。

3模板 vs 重载:一个定义,胜过 N 个重载

函数重载要每种类型写一个;函数模板写一个,编译器自动为用到的类型各生成一份。

// 重载:每来一种类型就要再写一个 int myMax(int a, int b){ return a>b?a:b; } double myMax(double a, double b){ return a>b?a:b; } // 模板:一个定义,装下任意支持 > 的类型 template<typename T> T myMax(T a, T b){ return a>b?a:b; } myMax(3, 7); // 实例化 int 版 myMax(2.5, 1.9); // 实例化 double 版 myMax(std::string("a"), std::string("b")); // 实例化 string 版
前提:模板体内的操作,该类型必须支持(如 >、+)。类型不支持时,用到它的那次实例化才报错。

!易错点

① 忘写 template<typename T> 那行——没这行 T 就是普通类型名,直接编译错。
② 调用时参数类型不一致——myMax(3, 2.5),T 该是 int 还是 double?编译器推不出来会报错。
③ 模板体内用了类型不支持的操作——不是写模板时就报,是用到该类型时才在实例化处报错。
④ 误以为模板会编译成一份共享代码——实际每种用到的类型各生成一份,代码体积会变大。

?跨学科:函数模板,就像"一套万用模具"

同一套模具(模板),倒不同材料(int / double / string),就产出不同"零件"(实例)。模具本身不是成品,只有倒入具体材料(调用具体类型)才成型。

像"给所有订单打同一个发货流程模板":模板写一次,套用不同订单类型;也像"一份通用报销表":谁填谁的类型,表不变。核心是把"共性的流程"和"可变的类型"分离。

✎练一练

template<typename T> 中的 T 代表什么?
T 是类型参数(占位符),模板实例化时被调用方传入的实际类型替换。
调用 myMax(3, 7) 时,函数模板如何变成可调用的函数?
调用具体类型时,编译器现场实例化出该类型的函数版本,然后照常调用。
相比"为每种类型各写一个函数重载",函数模板的核心优势是?
模板一个定义装任意类型(自动实例化),重载需逐类型手写。这是 STL 能适配所有容器/类型的根基。