036-C++ 模板

模板是 C++ 中的一种通用编程技术,允许函数或类在定义时不具体指定数据类型,而是在使用时根据实际类型实例化。模板使代码更加灵活且可重用,是泛型编程(Generic Programming)的核心。


1. 为什么需要模板?

在编写函数或类时,如果需要支持多种数据类型,通常会编写多个版本的代码,导致代码冗余且难以维护。模板提供了一种更优雅的解决方案,通过定义一次模板,可以支持多种数据类型。

示例:使用模板前后对比

没有模板的实现(函数重载)
#include 
using namespace std;

int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {
    return a + b;
}

int main() {
    cout << add(3, 4) << endl;       // 调用 int 版本
    cout << add(3.5, 4.5) << endl;  // 调用 double 版本
    return 0;
}
使用模板的实现
#include 
using namespace std;

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

int main() {
    cout << add(3, 4) << endl;       // 实例化 int 版本
    cout << add(3.5, 4.5) << endl;  // 实例化 double 版本
    return 0;
}

输出

7
8

说明

  • 使用模板后,只需要编写一次函数就可以支持多种数据类型。

2. 函数模板

函数模板用于定义能够处理不同数据类型的函数。

2.1 函数模板定义

template 
返回类型 函数名(参数列表) {
    // 函数体
}
  • template:定义模板的关键字。
  • :模板参数,T 是占位符,可以用任何合法的标识符代替。
  • T:表示函数的参数和返回值类型。

2.2 示例:函数模板

#include 
using namespace std;

template 
T maxOf(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    cout << "Max of 10 and 20: " << maxOf(10, 20) << endl;          // 实例化为 int
    cout << "Max of 3.5 and 2.7: " << maxOf(3.5, 2.7) << endl;      // 实例化为 double
    cout << "Max of 'A' and 'Z': " << maxOf('A', 'Z') << endl;      // 实例化为 char
    return 0;
}

输出

Max of 10 and 20: 20
Max of 3.5 and 2.7: 3.5
Max of 'A' and 'Z': Z

2.3 多个模板参数

函数模板可以支持多个模板参数。

示例:多个模板参数
#include 
using namespace std;

template 
void display(T1 a, T2 b) {
    cout << "First: " << a << ", Second: " << b << endl;
}

int main() {
    display(10, 20.5);        // T1 为 int,T2 为 double
    display("Hello", 100);    // T1 为 const char*,T2 为 int
    return 0;
}

输出

First: 10, Second: 20.5
First: Hello, Second: 100

2.4 显式实例化与自动推导

  • 自动推导:编译器会根据调用模板函数时传递的参数,推导模板参数的类型。
  • 显式实例化:可以通过显式指定模板参数来实例化函数。
示例:显式实例化
#include 
using namespace std;

template 
T square(T x) {
    return x * x;
}

int main() {
    cout << square(5) << endl;            // 自动推导为 int
    cout << square(5.5) << endl; // 显式实例化为 double
    return 0;
}

输出

25
30.25

3. 类模板

类模板用于定义能够处理不同数据类型的类。

3.1 类模板定义

template 
class 类名 {
public:
    T 数据成员;

    类名(T 参数) : 数据成员(参数) {}

    void display() {
        cout << 数据成员 << endl;
    }
};

3.2 示例:类模板

#include 
using namespace std;

template 
class Box {
private:
    T value;

public:
    Box(T val) : value(val) {}

    void display() {
        cout << "Value: " << value << endl;
    }
};

int main() {
    Box intBox(100);      // 实例化为 int
    Box doubleBox(3.14); // 实例化为 double

    intBox.display();
    doubleBox.display();

    return 0;
}

输出

Value: 100
Value: 3.14

3.3 多个模板参数

类模板也可以支持多个模板参数。

示例:多个模板参数的类模板
#include 
using namespace std;

template 
class Pair {
private:
    T1 first;
    T2 second;

public:
    Pair(T1 a, T2 b) : first(a), second(b) {}

    void display() {
        cout << "First: " << first << ", Second: " << second << endl;
    }
};

int main() {
    Pair p1(10, 3.14); // T1 为 int,T2 为 double
    Pair p2("Age", 25); // T1 为 string,T2 为 int

    p1.display();
    p2.display();

    return 0;
}

输出

First: 10, Second: 3.14
First: Age, Second: 25

4. 模板的特化

模板特化允许为特定的数据类型提供专门的实现,而其他类型仍然使用通用模板。

4.1 全特化

针对某种特定类型提供完全不同的实现。

示例:函数模板的全特化
#include 
using namespace std;

template 
T maxOf(T a, T b) {
    return (a > b) ? a : b;
}

// 特化版本
template <>
const char* maxOf(const char* a, const char* b) {
    return (strcmp(a, b) > 0) ? a : b;
}

int main() {
    cout << maxOf(10, 20) << endl;            // 使用通用模板
    cout << maxOf("apple", "orange") << endl; // 使用特化版本

    return 0;
}

输出

20
orange

4.2 偏特化(类模板专用)

偏特化允许对模板的部分参数进行特化。

示例:类模板的偏特化
#include 
using namespace std;

// 通用模板
template 
class Pair {
public:
    void display() {
        cout << "Generic template" << endl;
    }
};

// 偏特化:当两个参数类型相同时
template 
class Pair {
public:
    void display() {
        cout << "Specialized template for same types" << endl;
    }
};

int main() {
    Pair p1;
    Pair p2;

    p1.display(); // 通用模板
    p2.display(); // 特化模板

    return 0;
}

输出

Generic template
Specialized template for same types

5. 模板的优点与限制

5.1 优点

  1. 代码复用:通过一次定义,支持多种数据类型。
  2. 类型安全:编译器会根据模板参数进行类型检查。
  3. 提高可读性:减少重复代码。

5.2 限制

  1. 编译时间长:每个模板实例化都会生成独立的代码,增加编译时间。
  2. 调试复杂:模板错误信息可能较难理解。
  3. 代码膨胀:模板实例化可能导致生成大量重复代码,增加程序体积。

6. 总结

6.1 模板的核心概念

  1. 函数模板:定义支持多种类型的函数。
  2. 类模板:定义支持多种类型的类。
  3. 模板特化:为特定类型提供特化实现。

6.2 模板的实际应用

  1. 容器类:如 std::vectorstd::map 等。
  2. 算法库:如 std::sortstd::find 等。
  3. 通用工具:如泛型函数和类。

通过模板,C++ 提供了强大的泛型编程能力,极大地提高了代码的可复用性和灵活性,同时保持了类型安全性。


C++ 模板的高级应用

在之前的内容中,我们学习了 C++ 模板的基本使用,包括函数模板、类模板以及模板特化等内容。在本节中,我们将进一步探讨模板的高级功能和实际应用,包括模板的递归、模板元编程、可变参数模板以及模板与 STL 的结合。


7. 模板的递归

模板递归是一种强大的技术,允许通过递归模板的方式来完成编译时计算(如阶乘、斐波那契数等)。

7.1 示例:阶乘的模板递归

#include 
using namespace std;

// 基本模板
template 
struct Factorial {
    static const int value = N * Factorial::value;  // 递归调用
};

// 特化模板(递归终止条件)
template <>
struct Factorial<0> {
    static const int value = 1;
};

int main() {
    cout << "Factorial of 5: " << Factorial<5>::value << endl;  // 计算 5!
    cout << "Factorial of 10: " << Factorial<10>::value << endl;  // 计算 10!
    return 0;
}

输出

Factorial of 5: 120
Factorial of 10: 3628800

说明

  • 模板递归在编译时完成计算。
  • Factorial<5>::value 表示 5!,通过模板递归计算得出。

7.2 示例:斐波那契数列的模板递归

#include 
using namespace std;

// 基本模板
template 
struct Fibonacci {
    static const int value = Fibonacci::value + Fibonacci::value;
};

// 特化模板(递归终止条件)
template <>
struct Fibonacci<0> {
    static const int value = 0;
};

template <>
struct Fibonacci<1> {
    static const int value = 1;
};

int main() {
    cout << "Fibonacci(10): " << Fibonacci<10>::value << endl;  // 计算第 10 项
    cout << "Fibonacci(15): " << Fibonacci<15>::value << endl;  // 计算第 15 项
    return 0;
}

输出

Fibonacci(10): 55
Fibonacci(15): 610

8. 模板元编程(Template Metaprogramming)

模板元编程(TMP)是一种使用模板在编译时完成计算的编程技术,广泛用于优化代码和生成复杂的编译时逻辑。

8.1 编译时判断

通过模板实现类似 if-else 的编译时分支判断。

示例:判断是否为偶数
#include 
using namespace std;

// 判断是否为偶数
template 
struct IsEven {
    static const bool value = (N % 2 == 0);  // 编译时计算
};

int main() {
    cout << "Is 4 even? " << (IsEven<4>::value ? "Yes" : "No") << endl;
    cout << "Is 7 even? " << (IsEven<7>::value ? "Yes" : "No") << endl;
    return 0;
}

输出

Is 4 even? Yes
Is 7 even? No

8.2 编译时最大值

通过模板递归计算数组的最大值。

示例:编译时求最大值
#include 
using namespace std;

// 获取最大值
template 
struct Max {
    static const int value = (A > B) ? A : B;
};

int main() {
    cout << "Max of 10 and 20: " << Max<10, 20>::value << endl;
    cout << "Max of 42 and 15: " << Max<42, 15>::value << endl;
    return 0;
}

输出

Max of 10 and 20: 20
Max of 42 and 15: 42

9. 可变参数模板

C++11 引入了可变参数模板,允许模板接受任意数量的模板参数。这大大增强了模板的灵活性。

9.1 示例:打印可变数量的参数

#include 
using namespace std;

// 基本模板:递归终止
void print() {
    cout << endl;
}

// 可变参数模板
template 
void print(T first, Args... rest) {
    cout << first << " ";
    print(rest...);  // 递归调用
}

int main() {
    print(1, 2.5, "Hello", 'A');  // 打印多种类型的参数
    return 0;
}

输出

1 2.5 Hello A

说明

  • Args... rest 表示可变参数包。
  • 通过递归展开参数包,逐一处理参数。

9.2 示例:可变参数模板与编译时计算

通过可变参数模板计算任意数量参数的总和。

#include 
using namespace std;

// 递归终止
template 
T sum(T value) {
    return value;
}

// 可变参数模板
template 
T sum(T first, Args... rest) {
    return first + sum(rest...);  // 递归计算
}

int main() {
    cout << "Sum: " << sum(1, 2, 3, 4, 5) << endl;  // 求和
    cout << "Sum: " << sum(10.5, 20.3, 30.2) << endl;
    return 0;
}

输出

Sum: 15
Sum: 61

10. 模板与 STL 的结合

标准模板库(STL)是 C++ 模板的经典应用。STL 提供了通用的容器类和算法,通过模板实现了高度的复用性和灵活性。

10.1 使用模板容器

STL 容器(如 std::vector)通过模板支持任意类型的数据。

示例:模板容器
#include 
#include 
using namespace std;

template 
void displayVector(const vector& vec) {
    for (const T& val : vec) {
        cout << val << " ";
    }
    cout << endl;
}

int main() {
    vector intVec = {1, 2, 3, 4};
    vector strVec = {"Hello", "World"};

    displayVector(intVec);
    displayVector(strVec);

    return 0;
}

输出

1 2 3 4 
Hello World

10.2 自定义比较函数

模板允许为 STL 容器提供自定义的比较逻辑。

示例:自定义比较逻辑
#include 
#include 
using namespace std;

// 自定义比较函数
struct Compare {
    bool operator()(int a, int b) const {
        return a > b;  // 降序排列
    }
};

int main() {
    set mySet = {3, 1, 4, 1, 5, 9};
    for (int val : mySet) {
        cout << val << " ";
    }
    return 0;
}

输出

9 5 4 3 1

11. 模板的优雅设计

模板可以与现代 C++ 特性(如类型推导、智能指针等)结合,编写更优雅的代码。

11.1 类型推导与模板

C++14 引入了自动返回值推导,简化了模板的定义。

示例:自动返回值推导
#include 
using namespace std;

template 
auto add(T1 a, T2 b) {
    return a + b;  // 自动推导返回值类型
}

int main() {
    cout << add(3, 4.5) << endl;
    return 0;
}

输出

7.5

12. 总结

12.1 模板的核心功能

  1. 函数模板:定义支持多种数据类型的函数。
  2. 类模板:定义支持多种数据类型的类。
  3. 模板特化:为特定类型提供专门实现。
  4. 可变参数模板:支持任意数量的模板参数。

12.2 模板的高级应用

  1. 模板递归:用于编译时计算复杂逻辑。
  2. 模板元编程:实现编译时的逻辑判断和计算。
  3. 与 STL 结合:模板是 STL 的核心实现技术。

12.3 模板的优点

  • 提高代码复用性。
  • 支持类型安全的编译时检查。
  • 提供泛型编程能力。

通过模板,C++ 实现了极高的灵活性和性能,是语言的一大特色。在实际项目中,模板广泛应用于泛型库(如 STL)、编译时优化以及复杂算法的实现,极大地提高了编程效率和代码质量。

你可能感兴趣的:(C++,c++,算法,开发语言)