目录

  1. 模板概述
  2. 函数模板
  3. 类模板
  4. 模板特化
  5. 模板的非类型参数
  6. 模板的参数化
  7. 编译时计算与常量表达式
  8. 示例代码
  9. 参考资料

1. 模板概述

C++ 中的模板(Template)是实现泛型编程的一个强大特性,它允许开发者编写与类型无关的代码。在编写模板时,函数或类的实现并不依赖于特定的数据类型,而是在编译时由编译器根据实际传入的类型来生成相应的代码。模板支持函数模板和类模板,广泛应用于STL(标准模板库)等库中。

模板有助于提高代码的重用性和灵活性,使得程序能够处理不同类型的输入而不需要重复编写相同的逻辑。


2. 函数模板

函数模板允许你编写一个函数,能够处理不同类型的参数。编译器会根据传入的参数类型自动推导出函数所需的代码。

定义函数模板:

#include <iostream>
using namespace std;

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

int main() {
    cout << add(3, 4) << endl;     // 输出: 7
    cout << add(3.5, 4.2) << endl; // 输出: 7.7
    return 0;
}

解释:

  • template <typename T> 定义了一个模板,T 是占位符,代表一个类型。
  • add 函数可以接受任何类型的参数,只要它们是同一类型。
  • main 函数中,调用 add(3, 4)add(3.5, 4.2) 时,编译器会自动根据传入的参数类型(intdouble)推导出正确的模板实例。

3. 类模板

类模板允许你定义一个类,该类可以操作不同类型的数据。类模板的使用与函数模板类似,可以通过传入类型参数来实例化特定类型的类。

定义类模板:

#include <iostream>
using namespace std;

template <typename T>
class Box {
public:
    T value;
    Box(T v) : value(v) {}
    T getValue() {
        return value;
    }
};

int main() {
    Box<int> intBox(10);       // 实例化一个 Box 类型为 int 的对象
    Box<double> doubleBox(3.14); // 实例化一个 Box 类型为 double 的对象

    cout << intBox.getValue() << endl;    // 输出: 10
    cout << doubleBox.getValue() << endl; // 输出: 3.14

    return 0;
}

解释:

  • Box 是一个类模板,接受一个类型参数 T
  • 通过 Box<int>Box<double> 来创建不同类型的类实例。
  • 类的成员 value 类型根据模板参数 T 自动推导。

4. 模板特化

模板特化允许你为特定类型提供模板的自定义实现。模板特化可以分为两种类型:

  • 完全特化:为特定类型完全定义一个模板版本。
  • 偏特化:为某些特定的模板参数组合提供自定义实现。

完全特化示例:

#include <iostream>
using namespace std;

template <typename T>
T multiply(T a, T b) {
    return a * b;
}

// 完全特化 int 类型
template <>
int multiply<int>(int a, int b) {
    cout << "Specialized for int" << endl;
    return a * b;
}

int main() {
    cout << multiply(2.5, 3.5) << endl; // 使用泛型模板
    cout << multiply(2, 3) << endl;     // 使用完全特化的模板

    return 0;
}

解释:

  • int 类型提供了一个专门的 multiply 实现,这样调用 multiply(2, 3) 时会使用特化版本,而不是泛型版本。

5. 模板的非类型参数

模板可以接受除了类型参数外,还可以接受非类型参数(如整数、指针等)。非类型参数在编译时就确定值,可以用来做数组大小或其他编译时常量计算。

非类型模板参数示例:

#include <iostream>
using namespace std;

template <typename T, int size>
class Array {
public:
    T arr[size];
    void display() {
        for (int i = 0; i < size; ++i) {
            cout << arr[i] << " ";
        }
        cout << endl;
    }
};

int main() {
    Array<int, 5> intArray = {{1, 2, 3, 4, 5}};
    intArray.display(); // 输出: 1 2 3 4 5
    return 0;
}

解释:

  • Array 类模板有两个参数:T 类型和 size 非类型参数。
  • size 在编译时已经确定,用来指定数组的大小。

6. 模板的参数化

C++11 及以后的版本允许通过 template 参数化模板的类型和非类型参数。这使得模板的应用更加灵活,能够处理更加复杂的类型和数据。

示例:模板参数化

#include <iostream>
using namespace std;

template <typename T, typename U>
auto multiply(T a, U b) -> decltype(a * b) {
    return a * b;
}

int main() {
    cout << multiply(2, 3.5) << endl; // 输出: 7
    return 0;
}

解释:

  • multiply 函数模板接受两个类型的参数 TU,通过 decltype(a * b) 自动推导返回类型。

7. 编译时计算与常量表达式

模板可以在编译时进行常量计算,这是通过 constexpr 和模板常量参数来实现的。这使得模板能够在编译期进行更复杂的计算,而不是在运行时。

示例:编译时计算

#include <iostream>
using namespace std;

template <int N>
constexpr int factorial() {
    return N * factorial<N - 1>();
}

template <>
constexpr int factorial<0>() {
    return 1;
}

int main() {
    cout << factorial<5>() << endl;  // 输出: 120
    return 0;
}

解释:

  • factorial 模板通过递归实现编译时计算阶乘。
  • 使用 constexpr 可以在编译时完成计算,避免运行时计算开销。

8. 示例代码

示例 1:函数模板

#include <iostream>
using namespace std;

template <typename T>
T square(T n) {
    return n * n;
}

int main() {
    cout << square(5) << endl;    // 输出: 25
    cout << square(3.5) << endl;  // 输出: 12.25
    return 0;
}

示例 2:类模板

#include <iostream>
using namespace std;

template <typename T>
class Pair {
public:
    T first, second;
    Pair(T a, T b) : first(a), second(b) {}
    void display() {
        cout << "First: " << first << ", Second: " << second << endl;
    }
};

int main() {
    Pair<int> intPair(1, 2);
    intPair.display();  // 输出: First: 1, Second: 2

    Pair<string> strPair("Hello", "World");
    strPair.display();  // 输出: First: Hello, Second: World

    return 0;
}


9. 参考资料


总结

C++ 模板是强大的泛型编程工具,可以帮助开发者编写高效、可重用的代码。通过函数模板和类模板,程序员能够创建类型无关的函数和类。在使用模板时,我们可以利用模板特化、非类型参数和参数化等高级特性来进一步优化代码结构和功能。模板广泛应用于 C++ 标准库(如 STL),是 C++ 编程的重要组成部分。