模板特化
本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 66 课,共 104 课。
有时,通用模板并不适用于所有类型。例如,使用 > 比较 C 风格字符串时,比较的是指针地址,而不是实际文本。模板特化让你可以为特定类型提供自定义实现,同时为其他类型保留通用版本。
全特化会替换某个特定类型的整个模板。你可以使用空的模板参数列表声明它,并指定具体类型:
// 主模板
template <typename T>
class Printer {
public:
void print(T value) {
std::cout << value << std::endl;
}
};
// 针对 const char* 的完全特化
template <>
class Printer<const char*> {
public:
void print(const char* value) {
std::cout << "String: " << value << std::endl;
}
};
Printer<int> intPrinter;
intPrinter.print(42); // 输出:42
Printer<const char*> strPrinter;
strPrinter.print("hello"); // 输出:String: hello函数模板也可以进行特化:
template <typename T>
bool isEqual(T a, T b) {
return a == b;
}
template <>
bool isEqual<const char*>(const char* a, const char* b) {
return std::strcmp(a, b) == 0;
}
isEqual(5, 5); // 使用通用版本
isEqual("hi", "hi"); // 使用特化版本编译器总是优先选择最具体的匹配项。如果存在适用于当前所用确切类型的特化版本,就会选择它,而不是通用模板。
挑战
简单让我们构建一个类型感知的格式化系统,演示模板特化如何让你为特定类型自定义行为,同时为其他所有类型保留通用的默认实现。
你将创建两个文件来组织模板代码:
Formatter.h:定义一个名为Formatter的类模板,用于格式化值以供显示。通用模板应适用于任何类型,你还会为需要特殊处理的类型创建特化版本。主
Formatter模板应包含:- 一个
format()方法,接收一个 T 类型的值,并打印:Value: <value>
为
bool创建一个全特化版本,打印易于理解的文本,而不是 1 或 0:format()方法应打印:Boolean: true或Boolean: false
为
const char*创建一个全特化版本,为字符串添加引号:format()方法应打印:String: "<value>"
还要创建一个名为
formatPair的函数模板,接收两个相同类型的值,并将它们一起打印为:Pair: [<first>, <second>]为
const char*创建formatPair的特化版本,为每个字符串加上引号:Pair: ["<first>", "<second>"]- 一个
main.cpp:读取 4 个输入(每个输入各占一行):- 一个整数
- 一个 double
- 一个以字符串形式表示的布尔值(
true或false) - 一个字符串值
创建相应的
Formatter对象,并为每种类型调用format(),以演示格式化器的用法:- 使用
Formatter<int>格式化整数 - 使用
Formatter<double>格式化 double - 使用
Formatter<bool>格式化布尔值(先将字符串输入转换为 bool) - 使用
Formatter<const char*>格式化字符串
接着演示函数模板特化:
- 用两个整数调用
formatPair:10 和 20 - 用两个 C 字符串调用
formatPair:"hello"和"world"
例如,输入 42、3.14、true 和 Hello 时:
Value: 42
Value: 3.14
Boolean: true
String: "Hello"
Pair: [10, 20]
Pair: ["hello", "world"]请注意,通用模板对整数和 double 的处理方式相同,而针对 bool 和 const char* 的特化版本则提供了自定义格式。编译器会自动为你使用的每种类型选择最具体的匹配版本。
亲手试试
#include <iostream>
#include <string>
#include "Formatter.h"
using namespace std;
int main() {
// 读取输入
int intVal;
double doubleVal;
string boolStr;
string strVal;
cin >> intVal;
cin >> doubleVal;
cin >> boolStr;
cin >> strVal;
// 将字符串转换为 bool 类型
bool boolVal = (boolStr == "true");
// TODO: 创建 Formatter<int>,并格式化整数
// TODO: 创建 Formatter<double>,并格式化双精度浮点数
// TODO: 创建 Formatter<bool>,并格式化布尔值
// TODO: 创建 Formatter<const char*>,并格式化字符串
// 提示:使用 strVal.c_str() 获取 const char*
// TODO: 用两个整数 10 和 20 调用 formatPair
// TODO: 用两个 C 字符串 "hello" 和 "world" 调用 formatPair
return 0;
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C++ 在线编译器