Menu
CoddyTech

函数模板

本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 64 课,共 104 课。

想象一下,你编写了一个函数来找出两个整数中的最大值,随后发现还需要为双精度浮点数编写相同的逻辑,之后还要为字符串编写一次。如果没有模板,你就得为每种类型分别编写几乎相同的函数。函数模板可以解决这个问题:你只需编写一次逻辑,编译器就会自动生成适用于特定类型的版本。

函数模板使用 template 关键字,后面跟着尖括号中的模板参数:

template <typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    std::cout << maximum(5, 3) << std::endl;       // 使用 int 版本
    std::cout << maximum(3.14, 2.71) << std::endl; // 使用 double 版本
    std::cout << maximum('a', 'z') << std::endl;   // 使用 char 版本
}

编译器会检查每次调用,并为特定类型生成一个具体函数。这个过程称为模板实例化。需要时,你也可以显式指定类型:

std::cout << maximum<double>(5, 3.14) << std::endl;  // 强制使用 double 版本

模板可以有多个类型参数,从而实现更灵活的设计:

template <typename T, typename U>
void printPair(T first, U second) {
    std::cout << first << ", " << second << std::endl;
}

printPair(42, "hello");    // T=int, U=const char*
printPair(3.14, 100);      // T=double, U=int

函数模板提供编译时多态,类型在编译代码时确定,而不是在运行时确定。这意味着与虚函数相比,运行时开销为零,因此模板非常适合对性能要求高的泛型代码。

challenge icon

挑战

简单

让我们使用函数模板构建一个实用工具包,创建可与任何兼容类型配合使用的可复用操作。你会将通用函数组织在头文件中,并在主程序里展示它们的灵活性。

你将创建两个文件:

  • MathUtils.h:定义一组执行常见操作的函数模板:

    minimum:一个模板函数,接收两个类型相同的值,并返回较小的那个。

    clamp:一个模板函数,接收三个参数:一个值、下界和上界。它会返回限制在边界范围内的值(如果 value 小于 low,则返回 low;如果 value 大于 high,则返回 high;否则返回 value 本身)。

    swapValues:一个模板函数,接收两个类型相同的引用,并交换它们的值。

  • main.cpp:读取 6 个输入(每个输入单独占一行):

    1. 第一个整数
    2. 第二个整数
    3. 要进行范围限制的 double 值
    4. 下界(double)
    5. 上界(double)
    6. 一个字符

    通过以下操作展示你的模板:

    1. 找出两个整数中的最小值并打印:Min of <a> and <b>: <result>
    2. 找出字符 'm' 和你输入的字符中的最小值,并打印:Min of m and <char>: <result>
    3. 对 double 值进行范围限制并打印:Clamp <value> to [<low>, <high>]: <result>
    4. 将第一个整数限制在范围 [0, 100] 内并打印:Clamp <value> to [0, 100]: <result>
    5. 交换两个整数并打印:After swapValues: <a>, <b>

例如,输入 25、10、3.7、1.0、5.0 和 z 时:

Min of 25 and 10: 10
Min of m and z: m
Clamp 3.7 to [1, 5]: 3.7
Clamp 25 to [0, 100]: 25
After swapValues: 10, 25

注意,每个模板函数都能轻松处理整数、double 和字符:编译器会为你使用的每种类型生成相应版本。你的 swapValues 函数应通过引用修改原始变量,展示模板也能像普通函数一样使用引用参数。

亲手试试

#include <iostream>
#include "MathUtils.h"
using namespace std;

int main() {
    // 读取输入
    int a, b;
    double value, low, high;
    char ch;
    
    cin >> a;
    cin >> b;
    cin >> value;
    cin >> low;
    cin >> high;
    cin >> ch;
    
    // TODO: 用 minimum 模板求两个整数中的较小值
    // 输出:"Min of <a> and <b>: <result>"
    
    // TODO: 用 minimum 模板求 'm' 和输入字符中的较小值
    // 输出:"Min of m and <char>: <result>"
    
    // TODO: 对 double 值使用 clamp 模板
    // 输出:"Clamp <value> to [<low>, <high>]: <result>"
    
    // TODO: 对第一个整数使用 clamp 模板,范围为 [0, 100]
    // 输出:"Clamp <value> to [0, 100]: <result>"
    
    // TODO: 对两个整数使用 swapValues 模板
    // 输出:"After swapValues: <a>, <b>"
    
    return 0;
}
quiz icon自我测试

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

面向对象编程中的所有课

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