• C++
  • C++ 函数模板学习笔记教程

  • @ 2025-8-10 14:11:41

C++ 函数模板学习笔记教程

1. 什么是函数模板

函数模板(Function Template)是C++中的一种代码复用机制,它允许我们创建一个通用的函数定义,而不指定具体的数据类型。编译器会根据调用时提供的参数类型,自动生成相应类型的函数实例。

函数模板的主要优势:

  • 代码复用:一份代码可以处理多种数据类型
  • 类型安全:在编译时进行类型检查
  • 灵活性:无需为每种数据类型编写重复代码

2. 函数模板的基本语法

函数模板的基本结构如下:

template <typename T>  // 模板参数声明
返回类型 函数名(参数列表) {
    // 函数体,可使用类型T
}

其中:

  • template 是关键字,表明这是一个模板
  • <typename T> 是模板参数列表,T是类型参数(也可以用class代替typename
  • T可以在函数参数、返回值和函数体内作为类型使用

3. 第一个函数模板示例

下面是一个实现两个数相加的函数模板:

#include <iostream>

// 函数模板定义
template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    // 自动推导类型为int
    int int_sum = add(3, 5);
    std::cout << "整数相加: " << int_sum << std::endl;  // 输出 8
    
    // 自动推导类型为double
    double double_sum = add(2.5, 3.7);
    std::cout << "浮点数相加: " << double_sum << std::endl;  // 输出 6.2
    
    // 显式指定类型
    float float_sum = add<float>(1.2f, 3.4f);
    std::cout << "浮点数相加: " << float_sum << std::endl;  // 输出 4.6
    
    return 0;
}

4. 函数模板的实例化

当我们调用函数模板时,编译器会根据传入的参数类型生成特定类型的函数,这个过程称为模板实例化。

实例化有两种方式:

  1. 隐式实例化:编译器根据传入的参数自动推断类型

    int result = add(5, 10);  // 隐式实例化为add<int>
    
  2. 显式实例化:手动指定模板参数类型

    double result = add<double>(3.14, 2.71);  // 显式指定为double类型
    

5. 多参数函数模板

函数模板可以有多个类型参数,用逗号分隔:

#include <iostream>
#include <string>

// 多参数函数模板
template <typename T1, typename T2>
void print_pair(T1 first, T2 second) {
    std::cout << "Pair: " << first << ", " << second << std::endl;
}

int main() {
    print_pair(10, 3.14);           // T1=int, T2=double
    print_pair("Hello", 42);        // T1=const char*, T2=int
    print_pair(std::string("Age"), 25);  // T1=std::string, T2=int
    
    return 0;
}

6. 函数模板的重载

函数模板可以像普通函数一样被重载,包括:

  • 模板函数之间的重载
  • 模板函数与普通函数的重载
#include <iostream>

// 基本模板:两个参数相加
template <typename T>
T add(T a, T b) {
    std::cout << "使用模板 add(T, T): ";
    return a + b;
}

// 重载模板:三个参数相加
template <typename T>
T add(T a, T b, T c) {
    std::cout << "使用模板 add(T, T, T): ";
    return a + b + c;
}

// 普通函数:处理字符串拼接
std::string add(const char* a, const char* b) {
    std::cout << "使用普通函数 add(const char*, const char*): ";
    return std::string(a) + std::string(b);
}

int main() {
    std::cout << add(2, 3) << std::endl;                // 使用两个参数的模板
    std::cout << add(2, 3, 4) << std::endl;             // 使用三个参数的模板
    std::cout << add("Hello, ", "World!") << std::endl;  // 使用普通函数
    
    return 0;
}

注意:当普通函数和模板函数都能匹配时,编译器会优先选择普通函数。

7. 模板参数的默认值

C++11及以后的标准允许为模板参数指定默认值:

template <typename T = int>  // 指定int为默认类型
T multiply(T a, T b) {
    return a * b;
}

// 调用时可以不指定类型,使用默认的int
int result1 = multiply(3, 4);       // 使用默认类型int
double result2 = multiply<double>(2.5, 4.0);  // 指定为double

8. 非类型模板参数

除了类型参数,模板还可以有非类型参数,它们是编译时常量:

#include <iostream>

// 非类型模板参数示例:数组求和
template <typename T, int N>
T sum_array(T (&arr)[N]) {
    T sum = 0;
    for (int i = 0; i < N; ++i) {
        sum += arr[i];
    }
    return sum;
}

int main() {
    int int_arr[] = {1, 2, 3, 4, 5};
    std::cout << "整数数组的和: " << sum_array(int_arr) << std::endl;  // 15
    
    double double_arr[] = {1.1, 2.2, 3.3};
    std::cout << "浮点数数组的和: " << sum_array(double_arr) << std::endl;  // 6.6
    
    return 0;
}

9. 函数模板的特化

当需要为特定类型提供不同的实现时,可以使用模板特化:

#include <iostream>
#include <string>

// 通用模板
template <typename T>
T max_value(T a, T b) {
    std::cout << "使用通用模板: ";
    return (a > b) ? a : b;
}

// 对const char*类型的特化
template <>
const char* max_value<const char*>(const char* a, const char* b) {
    std::cout << "使用const char*特化版本: ";
    return (std::strcmp(a, b) > 0) ? a : b;
}

int main() {
    std::cout << max_value(10, 20) << std::endl;  // 使用通用模板
    std::cout << max_value("apple", "banana") << std::endl;  // 使用特化版本
    
    return 0;
}

10. 函数模板的注意事项

  1. 模板定义通常放在头文件中:因为模板实例化需要看到完整的模板定义。

  2. 隐式类型转换受限:当使用模板时,参数的类型推导不进行隐式类型转换。

    add(3, 5.5);  // 错误!int和double类型不匹配
    add<double>(3, 5.5);  // 正确,显式指定类型
    
  3. 并非所有类型都适用:模板函数中的操作必须对所使用的类型有效。

    // 这个模板不能用于不支持+运算符的类型
    template <typename T>
    T add(T a, T b) { return a + b; }
    
  4. 编译错误可能难以理解:模板的错误信息通常比较复杂,需要仔细分析。

11. 总结

函数模板是C++中实现泛型编程的强大工具,它允许我们编写与类型无关的代码,提高代码复用性和灵活性。

掌握函数模板需要理解:

  • 基本语法和使用方法
  • 模板实例化机制
  • 模板重载和特化
  • 非类型模板参数的应用

通过合理使用函数模板,可以编写出更加通用、灵活且高效的C++代码。

0 条评论

目前还没有评论...