Menu
CoddyTech

模板特化

本课属于 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");        // 使用特化版本

编译器总是优先选择最具体的匹配项。如果存在适用于当前所用确切类型的特化版本,就会选择它,而不是通用模板。

challenge icon

挑战

简单

让我们构建一个类型感知的格式化系统,演示模板特化如何让你为特定类型自定义行为,同时为其他所有类型保留通用的默认实现。

你将创建两个文件来组织模板代码:

  • 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 个输入(每个输入各占一行):
    1. 一个整数
    2. 一个 double
    3. 一个以字符串形式表示的布尔值(true 或 false)
    4. 一个字符串值

    创建相应的 Formatter 对象,并为每种类型调用 format(),以演示格式化器的用法:

    1. 使用 Formatter<int> 格式化整数
    2. 使用 Formatter<double> 格式化 double
    3. 使用 Formatter<bool> 格式化布尔值(先将字符串输入转换为 bool)
    4. 使用 Formatter<const char*> 格式化字符串

    接着演示函数模板特化:

    1. 用两个整数调用 formatPair:10 和 20
    2. 用两个 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;
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C++ 在线编译器