模板

C++ 中的模板(Template)是一种强大的泛型编程工具,使得函数和类可以处理多种类型的参数,而无需重写代码。模板使得编写通用的代码变得更加灵活和高效,广泛应用于标准模板库(STL)中。

C++ 中有两种主要的模板:

  1. 函数模板(Function Template)

  2. 类模板(Class Template)

1. 函数模板

函数模板允许你编写通用的函数,不需要为不同的数据类型重复编写函数。编译器在使用时根据传递的参数类型生成相应的函数实例。

1.1 定义和使用函数模板

template <typename T>
T add(T a, T b) {
    return a + b;
}
  • template <typename T>:表示声明一个模板,T 是占位符类型,可以是任意数据类型。

  • T add(T a, T b):这是一个返回类型为 T 的函数,参数类型也都是 T,可以传递任何类型的参数,只要支持 + 运算符。

示例

#include <iostream>
using namespace std;

template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    int x = 10, y = 20;
    double a = 1.5, b = 2.5;

    // 使用模板函数
    cout << "add(x, y) = " << add(x, y) << endl;   // 整数加法
    cout << "add(a, b) = " << add(a, b) << endl;   // 浮点数加法

    return 0;
}

1.2 函数模板的类型推导

编译器可以根据传递的参数类型自动推导模板类型:

2. 类模板

类模板允许你为多个数据类型设计通用的类,而不需要针对每种类型编写不同的类。

2.1 定义和使用类模板

  • template <typename T>:定义一个模板类,T 是占位符类型。

  • Box<T>:表示一个泛型类,T 可以是任何类型,类中的成员变量 value 和方法 getValue() 都使用类型 T

示例

输出:

3. 模板的特化

模板特化允许你为特定的数据类型提供特定的实现,而不使用通用的模板版本。这在某些类型有特殊处理需求时非常有用。

3.1 函数模板特化

3.2 类模板特化

4. 模板的部分特化

类模板还可以进行部分特化,即对某些特定类型进行定制化处理,而保留其他类型的通用性。

5. 模板的应用场景

  • 泛型编程:模板使得编写通用的函数和类成为可能,避免了重复代码。

  • 容器类:C++ 标准模板库(STL)中的容器类(如 std::vectorstd::mapstd::list)和算法都基于模板实现,能够处理不同类型的数据。

  • 算法库:通过模板,算法可以适用于多种数据类型而无需修改实现。

6. 模板与内联

模板代码一般在头文件中定义,原因是模板代码只有在使用时才会生成实际的函数或类,因此编译器需要在使用模板时知道其定义。

7. 模板的编译过程

模板在编译时会进行两步检查:

  1. 模板定义检查:编译器检查模板语法是否正确,但不会生成实际代码。

  2. 模板实例化:当使用模板时,编译器根据具体类型实例化模板并生成实际的函数或类代码。

8. 模板的优缺点

优点:

  • 代码复用:通过模板,编写一次代码可以适用于多种数据类型,减少了重复代码。

  • 类型安全:模板提供了类型安全的编程方式,编译时会根据类型进行检查,避免了运行时类型错误。

缺点:

  • 编译时间增加:模板代码在使用时才进行实例化,这可能会增加编译时间。

  • 代码膨胀:不同类型的模板实例化会生成不同的代码,这可能导致编译后的代码体积增大。

9. 模板的高级特性

  • 模板模板参数:可以在模板中传递模板作为参数。

  • SFINAE(Substitution Failure Is Not An Error):模板替换失败并不会导致编译错误,而是尝试其他的匹配。

  • 变参模板(Variadic Templates):允许模板接受任意数量的参数。

总结

模板是 C++ 中实现泛型编程的核心工具。通过模板,程序员可以编写通用代码,并为不同类型提供一致的接口,提升了代码的可重用性和灵活性。

Last updated