楼层: 首页/ 软件技术/ 现代 C++/ 模板与泛型:一套代码通吃所有类型
6

模板与泛型:一套代码通吃所有类型

Templates · Concepts

你写了个 int add(int,int),又得写 double add(double,double)——烦不烦?模板就是"参数化类型":写一份,编译器帮你为每种用到的类型生成一份。STL 整个就是模板写出来的。

函数模板与类模板

// 函数模板:T 是个占位类型,调用时才确定 template<typename T> T add(T a, T b) { return a + b; } add(1, 2); // T 被推成 int add(1.5, 2.5); // T 被推成 double,一份代码两用 // 类模板:STL 的 vector<T> 就是这么来的 template<typename T> class Box { T value; public: Box(T v) : value(v) {} T get() { return value; } }; Box<int> bi(42); Box<std::string> bs("hi");

进Concepts(C++20):给模板参数立规矩

老模板的报错信息以"人类看不懂"著称——类型不满足要求时,编译器能甩出 50 行长报错。C++20 的 concepts 让你直接声明"T 必须是能比较大小的""T 必须是数字",不满足时报错一目了然。写法如 template<std::integral T>。这是现代 C++ 泛型的巨大福音,也是"比 SFINAE 友好"的意思。

模板特化:给特殊类型开小灶

主模板对所有类型用同一套实现,但有时候某个类型需要特殊处理(比如 bool 不该按原样存)。这时用模板特化:为特定类型写一份"专属实现"。

函数模板全特化:为 const char* 写专门的比较逻辑

// 主模板:泛用版 template<class T> bool equal(T a, T b) { return a == b; } // 全特化:T 固定为 const char*,按字符串内容比,而不是比指针地址 template<> bool equal<const char*>(const char* a, const char* b) { return std::strcmp(a, b) == 0; } // 调用 equal("hi","hi") 自动走特化版本

类模板偏特化则更进一步:只固定一部分类型参数。比如"只对指针类型"给一份特别实现,"只对带某种元素的 vector"给另一份。业务里用得少,写库时常见,知道有这回事即可。

变参模板:一次接受任意多个类型参数

以前函数参数个数写死。变参模板(Args...,叫参数包)让你写"能接任意多个任意类型参数"的函数——std::make_unique<T>(args...)、tuple 就靠它。

变参模板:递归解包参数包(C++17 起可用更简洁的折叠表达式)

// 递归终止:0 个参数时什么都不做 void printAll() {} // 拆出第一个 head,剩下的 tail 递归打印 template<class Head, class... Tail> void printAll(Head head, Tail... tail) { std::cout << head << ' '; printAll(tail...); // 剩下的接着递归 } // 调用:printAll(1, "hi", 3.14) 输出 "1 hi 3.14 "

C++17 折叠表达式把递归解包压成一行,不用写终止函数,了解即可:(std::cout << ... << args) << '\n';。日常业务很少从零写变参模板,主要是读标准库源码时遇到。