C++ 模板(Templates)详细指南

1. 功能说明

本指南基于 templates.cpp 文件,详细介绍了 C++ 中模板的各种类型和用法,包括:

  • 函数模板:实现通用的函数,如最大值、最小值、交换值等
  • 类模板:实现通用的类,如盒子、栈、数组、对、智能指针等
  • 非类型模板参数:使用常量表达式作为模板参数
  • 模板特化:为特定类型提供专门的实现
  • 变参模板:处理可变数量的模板参数
  • 模板的实例化:隐式实例化和显式实例化

2. 代码解析

2.1 函数模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 1. 模板函数 - 最大值
template<typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}

// 2. 模板函数 - 最小值
template<typename T>
T minimum(T a, T b) {
return (a < b) ? a : b;
}

// 3. 模板函数 - 交换值
template<typename T>
void swapValues(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}

// 4. 模板函数 - 加法
template<typename T>
T add(T a, T b) {
return a + b;
}

// 5. 模板函数 - 混合类型加法(使用decltype自动推导返回类型)
template<typename T, typename U>
auto addMixed(T a, U b) -> decltype(a + b) {
return a + b;
}

// 6. 模板函数 - 数组求和
template<typename T, size_t N>
T sumArray(const T(&arr)[N]) {
T sum = 0;
for (size_t i = 0; i < N; ++i) {
sum += arr[i];
}
return sum;
}

解析

  • 函数模板使用 template<typename T>template<class T> 声明
  • typenameclass 在模板参数声明中是等价的
  • 可以有多个模板参数,如 template<typename T, typename U>
  • 可以使用 decltype 自动推导返回类型(C++11 特性)
  • 可以使用非类型模板参数,如 template<typename T, size_t N> 中的 size_t N

2.2 类模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// 7. 模板类 - 盒子(存储单个值)
template<typename T>
class Box {
private:
T value; // 存储的值

public:
// 构造函数
Box(T v) : value(v) {}

// 获取值
T getValue() const {
return value;
}

// 设置值
void setValue(T v) {
value = v;
}

// 显示内容
void display() const {
std::cout << "Box contains: " << value << std::endl;
}
};

// 8. 模板类 - 栈
template<typename T>
class Stack {
private:
T* elements; // 元素数组
int top; // 栈顶索引
int capacity; // 栈容量

public:
// 构造函数
Stack(int size = 10) : top(-1), capacity(size) {
elements = new T[capacity];
}

// 析构函数
~Stack() {
delete[] elements;
}

// 入栈
void push(T item) {
if (top < capacity - 1) {
elements[++top] = item;
} else {
std::cout << "Stack is full!" << std::endl;
}
}

// 出栈
T pop() {
if (top >= 0) {
return elements[top--];
}
std::cout << "Stack is empty!" << std::endl;
return T();
}

// 检查是否为空
bool isEmpty() const {
return top == -1;
}

// 检查是否已满
bool isFull() const {
return top == capacity - 1;
}
};

解析

  • 类模板使用 template<typename T> 声明
  • 模板类的成员函数可以在类内部定义,也可以在类外部定义
  • 在类外部定义模板类的成员函数时,需要指定模板参数
  • 模板类可以有多个模板参数,如 template<typename T1, typename T2>

2.3 带非类型参数的模板类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 9. 模板类 - 数组(带非类型参数)
template<typename T, int N>
class Array {
private:
T data[N]; // 固定大小的数组

public:
// 下标运算符重载(非const版本)
T& operator[](int index) {
return data[index];
}

// 下标运算符重载(const版本)
const T& operator[](int index) const {
return data[index];
}

// 获取数组大小
int size() const {
return N;
}

// 填充数组
void fill(T value) {
for (int i = 0; i < N; ++i) {
data[i] = value;
}
}

// 显示数组内容
void display() const {
std::cout << "Array elements: ";
for (int i = 0; i < N; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
};

解析

  • 非类型模板参数必须是常量表达式
  • 非类型模板参数可以是整数类型、枚举类型、指针类型、引用类型等
  • 非类型模板参数在编译时被求值,因此必须是编译时常量
  • 在上面的例子中,int N 是一个非类型模板参数,用于指定数组的大小

2.4 模板特化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 15. 模板特化 - 针对const char*类型的Box特化
template<>
class Box<const char*> {
private:
std::string value; // 使用std::string存储字符串

public:
// 构造函数
Box(const char* v) : value(v) {}

// 获取值
const char* getValue() const {
return value.c_str();
}

// 设置值
void setValue(const char* v) {
value = v;
}

// 显示内容
void display() const {
std::cout << "Box contains: " << value << std::endl;
}
};

解析

  • 模板特化使用 template<> 声明
  • 特化版本必须与原模板的接口保持一致
  • 特化版本可以有不同的实现,以适应特定类型的需求
  • 在上面的例子中,为 const char* 类型提供了特化版本,使用 std::string 来存储字符串,避免了字符指针的问题

2.5 其他模板类示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// 10. 模板类 - 对(相同类型)
template<typename T>
class Pair {
private:
T first; // 第一个元素
T second; // 第二个元素

public:
// 构造函数
Pair(T a, T b) : first(a), second(b) {}

// 获取第一个元素
T getFirst() const {
return first;
}

// 获取第二个元素
T getSecond() const {
return second;
}

// 设置第一个元素
void setFirst(T value) {
first = value;
}

// 设置第二个元素
void setSecond(T value) {
second = value;
}

// 显示内容
void display() const {
std::cout << "Pair: (" << first << ", " << second << ")" << std::endl;
}
};

// 11. 模板类 - 对(不同类型)
template<typename T1, typename T2>
class Pair2 {
private:
T1 first; // 第一个元素(类型T1)
T2 second; // 第二个元素(类型T2)

public:
// 构造函数
Pair2(T1 a, T2 b) : first(a), second(b) {}

// 获取第一个元素
T1 getFirst() const {
return first;
}

// 获取第二个元素
T2 getSecond() const {
return second;
}

// 显示内容
void display() const {
std::cout << "Pair: (" << first << ", " << second << ")" << std::endl;
}
};

// 12. 模板类 - 智能指针(简化版)
template<typename T>
class SmartPointer {
private:
T* ptr; // 原始指针

public:
// 构造函数
SmartPointer(T* p = nullptr) : ptr(p) {}

// 析构函数
~SmartPointer() {
delete ptr;
}

// 解引用运算符重载
T& operator*() {
return *ptr;
}

// 箭头运算符重载
T* operator->() {
return ptr;
}

// 获取原始指针
T* get() const {
return ptr;
}
};

// 13. 模板类 - 链表节点
template<typename T>
class Node {
public:
T data; // 节点数据
Node* next; // 指向下一个节点的指针

// 构造函数
Node(T value) : data(value), next(nullptr) {}
};

// 14. 模板类 - 单链表
template<typename T>
class LinkedList {
private:
Node<T>* head; // 链表头节点

public:
// 构造函数
LinkedList() : head(nullptr) {}

// 析构函数
~LinkedList() {
Node<T>* current = head;
while (current) {
Node<T>* next = current->next;
delete current;
current = next;
}
}

// 添加节点到链表末尾
void add(T value) {
Node<T>* newNode = new Node<T>(value);
if (!head) {
head = newNode;
} else {
Node<T>* current = head;
while (current->next) {
current = current->next;
}
current->next = newNode;
}
}

// 显示链表内容
void display() const {
Node<T>* current = head;
std::cout << "LinkedList: ";
while (current) {
std::cout << current->data << " -> ";
current = current->next;
}
std::cout << "nullptr" << std::endl;
}
};

解析

  • Pair 类模板演示了如何使用单个模板参数创建存储相同类型元素的对
  • Pair2 类模板演示了如何使用多个模板参数创建存储不同类型元素的对
  • SmartPointer 类模板演示了如何创建一个简单的智能指针
  • NodeLinkedList 类模板演示了如何创建一个通用的单链表

2.6 主函数 - 测试各种模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
int main() {
std::cout << "=== 1. 模板函数 ===" << std::endl;
std::cout << "最大值 of 10 and 20: " << maximum(10, 20) << std::endl;
std::cout << "最大值 of 3.14 and 2.71: " << maximum(3.14, 2.71) << std::endl;
std::cout << "最大值 of 'a' and 'z': " << maximum('a', 'z') << std::endl;

std::cout << "\n最小值 of 10 and 20: " << minimum(10, 20) << std::endl;
std::cout << "最小值 of 3.14 and 2.71: " << minimum(3.14, 2.71) << std::endl;

int x = 5, y = 10;
std::cout << "\n交换前: x = " << x << ", y = " << y << std::endl;
swapValues(x, y);
std::cout << "交换后: x = " << x << ", y = " << y << std::endl;

double a = 1.5, b = 2.5;
std::cout << "交换前: a = " << a << ", b = " << b << std::endl;
swapValues(a, b);
std::cout << "交换后: a = " << a << ", b = " << b << std::endl;

std::cout << "Add(3, 4) = " << add(3, 4) << std::endl;
std::cout << "Add(3.5, 4.5) = " << add(3.5, 4.5) << std::endl;
std::cout << "AddMixed(3, 4.5) = " << addMixed(3, 4.5) << std::endl;

// 测试数组求和函数
int intArray[] = {1, 2, 3, 4, 5};
double doubleArray[] = {1.1, 2.2, 3.3, 4.4};
std::cout << "\n数组求和: " << sumArray(intArray) << std::endl;
std::cout << "数组求和: " << sumArray(doubleArray) << std::endl;

std::cout << "\n=== 2. 模板类 Box ===" << std::endl;
Box<int> intBox(42);
intBox.display();

Box<double> doubleBox(3.14159);
doubleBox.display();

Box<std::string> stringBox("Hello Template!");
stringBox.display();

// 测试模板特化
Box<const char*> charBox("Specialized Template");
charBox.display();

std::cout << "\n=== 3. 模板类 Stack ===" << std::endl;
Stack<int> intStack(5);
intStack.push(10);
intStack.push(20);
intStack.push(30);

while (!intStack.isEmpty()) {
std::cout << "弹出: " << intStack.pop() << std::endl;
}

Stack<std::string> stringStack(3);
stringStack.push("First");
stringStack.push("Second");
stringStack.push("Third");

while (!stringStack.isEmpty()) {
std::cout << "弹出: " << stringStack.pop() << std::endl;
}

std::cout << "\n=== 4. 带非类型参数的模板类 Array ===" << std::endl;
Array<int, 5> intArrayObj;
for (int i = 0; i < intArrayObj.size(); ++i) {
intArrayObj[i] = i * 10;
}

intArrayObj.display();

// 测试fill方法
Array<double, 3> doubleArrayObj;
doubleArrayObj.fill(3.14);
doubleArrayObj.display();

std::cout << "\n=== 5. 模板类 Pair ===" << std::endl;
Pair<int> intPair(10, 20);
intPair.display();

Pair<double> doublePair(3.14, 2.71);
doublePair.display();

Pair2<std::string, int> mixedPair("Age", 25);
mixedPair.display();

Pair2<int, double> mixedPair2(100, 99.99);
mixedPair2.display();

std::cout << "\n=== 6. 模板类 SmartPointer ===" << std::endl;
SmartPointer<int> smartPtr(new int(100));
std::cout << "智能指针值: " << *smartPtr << std::endl;

SmartPointer<std::string> stringPtr(new std::string("Smart String"));
std::cout << "智能指针值: " << *stringPtr << std::endl;

std::cout << "\n=== 7. 模板类 LinkedList ===" << std::endl;
LinkedList<int> intList;
intList.add(10);
intList.add(20);
intList.add(30);
intList.display();

LinkedList<std::string> stringList;
stringList.add("Hello");
stringList.add("World");
stringList.display();

return 0;
}

解析

  • 测试了各种模板函数的使用,包括自动类型推导
  • 测试了各种模板类的使用,包括不同类型的实例化
  • 测试了模板特化的使用
  • 测试了带非类型参数的模板类的使用
  • 展示了模板在实际应用中的灵活性和通用性

3. 编译和运行说明

3.1 编译命令

使用以下命令编译 templates.cpp 文件:

1
g++ -std=c++11 -fexec-charset=GBK -o templates templates.cpp

参数说明:

  • -std=c++11:使用 C++11 标准
  • -fexec-charset=GBK:确保输出的中文字符正确显示
  • -o templates:指定输出可执行文件名为 templates

3.2 运行命令

编译成功后,使用以下命令运行程序:

1
2
./templates  # Linux/macOS
.\templates.exe # Windows

3.3 预期输出

运行程序后,您将看到类似以下的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
=== 1. 模板函数 ===
最大值 of 10 and 20: 20
最大值 of 3.14 and 2.71: 3.14
最大值 of 'a' and 'z': z

最小值 of 10 and 20: 10
最小值 of 3.14 and 2.71: 2.71

交换前: x = 5, y = 10
交换后: x = 10, y = 5
交换前: a = 1.5, b = 2.5
交换后: a = 2.5, b = 1.5
Add(3, 4) = 7
Add(3.5, 4.5) = 8
AddMixed(3, 4.5) = 7.5

数组求和: 15
数组求和: 11

=== 2. 模板类 Box ===
Box contains: 42
Box contains: 3.14159
Box contains: Hello Template!
Box contains: Specialized Template

=== 3. 模板类 Stack ===
弹出: 30
弹出: 20
弹出: 10
弹出: Third
弹出: Second
弹出: First
=== 4. 带非类型参数的模板类 Array ===
Array elements: 0 10 20 30 40
Array elements: 3.14 3.14 3.14

=== 5. 模板类 Pair ===
Pair: (10, 20)
Pair: (3.14, 2.71)
Pair: (Age, 25)
Pair: (100, 99.99)

=== 6. 模板类 SmartPointer ===
智能指针值: 100
智能指针值: Smart String

=== 7. 模板类 LinkedList ===
LinkedList: 10 -> 20 -> 30 -> nullptr
LinkedList: Hello -> World -> nullptr

4. 技术要点

4.1 模板的基本概念

  • 模板:是 C++ 的一种编程范式,允许创建通用的函数和类
  • 模板参数:在模板定义中使用的占位符,可以是类型参数或非类型参数
  • 模板实例化:根据具体类型创建模板的实例
  • 模板特化:为特定类型提供专门的实现

4.2 函数模板

  • 声明方式template<typename T> ReturnType functionName(Parameters)
  • 类型推导:编译器可以根据实参自动推导模板参数类型
  • 显式实例化:可以使用 <Type> 显式指定模板参数类型
  • 多个模板参数:可以有多个类型参数,如 template<typename T, typename U>
  • 默认模板参数:C++11 允许为模板参数提供默认值

4.3 类模板

  • 声明方式template<typename T> class ClassName { ... }
  • 实例化方式ClassName<Type> objectName(Arguments)
  • 成员函数:可以在类内部或外部定义,外部定义时需要指定模板参数
  • 静态成员:每个模板实例都有自己的静态成员副本
  • 模板作为参数:可以将模板类作为另一个模板的参数

4.4 非类型模板参数

  • 类型限制:必须是整数类型、枚举类型、指针类型、引用类型或 std::nullptr_t
  • 常量表达式:必须是编译时常量表达式
  • 使用场景:常用于指定数组大小、缓冲区大小等固定值
  • 示例template<typename T, int Size> class Array { ... }

4.5 模板特化

  • 全特化:为所有模板参数提供具体类型,如 template<> class Box<const char*> { ... }
  • 偏特化:为部分模板参数提供具体类型,如 template<typename T> class Pair<T, T> { ... }
  • 特化顺序:编译器会优先选择最匹配的特化版本
  • 特化的必要性:处理某些类型的特殊需求,如字符串指针

4.6 变参模板

  • 声明方式template<typename... Args> ReturnType functionName(Args... args)
  • 参数包Args... 表示模板参数包,args... 表示函数参数包
  • 展开参数包:使用递归或逗号表达式展开参数包
  • 使用场景:实现可变参数函数,如 std::tuplestd::function

4.7 模板的编译模型

  • 包含模型:模板定义必须在使用前可见,通常放在头文件中
  • 显式实例化模型:模板声明放在头文件中,定义放在源文件中,然后显式实例化
  • 编译错误:模板错误通常在实例化时才会被发现,称为 “late binding”

4.8 模板的优缺点

优点

  • 代码重用:编写一次代码,适用于多种类型
  • 类型安全:在编译时进行类型检查
  • 性能:没有运行时开销,因为模板在编译时实例化
  • 灵活性:可以创建高度通用的代码

缺点

  • 编译时间:模板会增加编译时间和目标代码大小
  • 错误信息:模板错误信息通常比较复杂,难以理解
  • 代码可读性:复杂的模板代码可能难以阅读和维护

5. 常见问题解答

5.1 什么是模板参数推导?

模板参数推导是指编译器根据函数调用的实参自动确定模板参数类型的过程。例如,当调用 maximum(10, 20) 时,编译器会推导出 Tint 类型。

5.2 如何处理模板中的类型不匹配问题?

  • 使用类型转换:确保实参类型可以隐式转换为模板参数类型
  • 显式指定模板参数:使用 <Type> 显式指定模板参数类型
  • 使用类型萃取:使用 std::enable_ifstd::is_same 等类型特性进行编译时类型检查
  • 提供特化版本:为特定类型提供专门的实现

5.3 模板特化和函数重载有什么区别?

  • 模板特化:是模板的一种特殊形式,为特定类型提供专门的实现
  • 函数重载:是为不同参数列表的函数提供不同的实现
  • 选择顺序:编译器会优先选择非模板函数,然后是模板特化,最后是通用模板

5.4 如何避免模板代码膨胀?

  • 使用共享实现:将通用代码提取到非模板基类中
  • 使用类型擦除:如 std::function 那样使用虚函数表
  • 显式实例化:只实例化需要的模板版本
  • 使用模板参数约束:减少不必要的实例化

5.5 什么是 SFINAE?

SFINAE (Substitution Failure Is Not An Error) 是 C++ 中的一个规则,指的是当模板参数替换失败时,这不是一个错误,而是会尝试其他重载版本。SFINAE 常用于模板元编程中进行编译时类型检查。

5.6 如何在模板中使用默认参数?

  • 函数模板template<typename T = int> T functionName(T a = T())
  • 类模板template<typename T = int> class ClassName { ... }
  • 非类型模板参数template<typename T, int N = 10> class Array { ... }

5.7 如何处理模板中的继承问题?

  • 模板类作为基类template<typename T> class Derived : public Base<T> { ... }
  • 基类依赖:在派生类中使用基类的成员时,需要使用 this->Base<T>:: 限定
  • 模板特化与继承:可以为派生类提供特化版本

6. 代码优化建议

6.1 合理使用模板

  • 只在必要时使用模板:对于简单的函数,普通函数可能更合适
  • 避免过度泛化:不要为了泛化而泛化,保持代码简洁
  • 考虑编译时间:过多的模板可能会显著增加编译时间

6.2 模板参数约束

  • 使用 C++20 概念:使用 concept 关键字约束模板参数类型
  • 使用类型特性:使用 std::enable_if 等类型特性进行编译时类型检查
  • 提供清晰的错误信息:当模板参数不符合要求时,提供明确的错误信息

6.3 模板代码组织

  • 声明与定义分离:对于简单模板,声明和定义都放在头文件中
  • 使用显式实例化:对于复杂模板,考虑使用显式实例化减少编译时间
  • 使用头文件保护:避免头文件重复包含

6.4 性能优化

  • 避免不必要的实例化:只实例化需要的模板版本
  • 使用移动语义:在模板中使用移动构造函数和移动赋值运算符
  • 考虑内联:对于简单的模板函数,考虑使用 inline 关键字

6.5 可读性和可维护性

  • 使用有意义的模板参数名:如 TValueTPolicyT
  • 添加注释:为模板参数和模板函数添加清晰的注释
  • 使用别名模板:使用 using 声明创建模板别名,提高可读性
  • 避免深层嵌套:避免过于复杂的模板嵌套,保持代码结构清晰

6.6 常见陷阱避免

  • 模板参数推导失败:确保实参类型与模板参数类型匹配
  • 二义性:避免模板特化和重载导致的二义性
  • 虚函数与模板:模板成员函数不能是虚函数
  • 默认模板参数:注意默认模板参数的顺序和依赖关系
  • 非类型模板参数的限制:确保非类型模板参数是编译时常量

7. 总结

模板是 C++ 中一种强大的编程工具,它允许创建通用的函数和类,提高代码重用性和类型安全性。通过本文的学习,您应该掌握了:

  • 函数模板的声明和使用
  • 类模板的声明和使用
  • 非类型模板参数的使用
  • 模板特化的实现和应用
  • 模板的编译和实例化机制
  • 模板的优缺点和最佳实践

合理使用模板可以使代码更加灵活、通用和高效,但也需要注意避免过度使用导致的编译时间增加和代码复杂性提高。在实际开发中,应根据具体需求选择合适的模板使用方式,平衡通用性和性能。

C++11 及以后的标准引入了许多模板相关的新特性,如类型推导、变参模板、模板别名等,这些特性进一步增强了模板的能力和易用性。随着 C++ 标准的不断发展,模板的功能和性能也在不断改进,为 C++ 程序员提供了更强大的工具。

templates.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

// 1. 模板函数 - 最大值
template<typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}

// 2. 模板函数 - 最小值
template<typename T>
T minimum(T a, T b) {
return (a < b) ? a : b;
}

// 3. 模板函数 - 交换值
template<typename T>
void swapValues(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}

// 4. 模板函数 - 加法
template<typename T>
T add(T a, T b) {
return a + b;
}

// 5. 模板函数 - 混合类型加法(使用decltype自动推导返回类型)
template<typename T, typename U>
auto addMixed(T a, U b) -> decltype(a + b) {
return a + b;
}

// 6. 模板函数 - 数组求和
template<typename T, size_t N>
T sumArray(const T(&arr)[N]) {
T sum = 0;
for (size_t i = 0; i < N; ++i) {
sum += arr[i];
}
return sum;
}

// 7. 模板类 - 盒子(存储单个值)
template<typename T>
class Box {
private:
T value; // 存储的值

public:
// 构造函数
Box(T v) : value(v) {}

// 获取值
T getValue() const {
return value;
}

// 设置值
void setValue(T v) {
value = v;
}

// 显示内容
void display() const {
std::cout << "Box contains: " << value << std::endl;
}
};

// 8. 模板类 - 栈
template<typename T>
class Stack {
private:
T* elements; // 元素数组
int top; // 栈顶索引
int capacity; // 栈容量

public:
// 构造函数
Stack(int size = 10) : top(-1), capacity(size) {
elements = new T[capacity];
}

// 析构函数
~Stack() {
delete[] elements;
}

// 入栈
void push(T item) {
if (top < capacity - 1) {
elements[++top] = item;
} else {
std::cout << "Stack is full!" << std::endl;
}
}

// 出栈
T pop() {
if (top >= 0) {
return elements[top--];
}
std::cout << "Stack is empty!" << std::endl;
return T();
}

// 检查是否为空
bool isEmpty() const {
return top == -1;
}

// 检查是否已满
bool isFull() const {
return top == capacity - 1;
}
};

// 9. 模板类 - 数组(带非类型参数)
template<typename T, int N>
class Array {
private:
T data[N]; // 固定大小的数组

public:
// 下标运算符重载(非const版本)
T& operator[](int index) {
return data[index];
}

// 下标运算符重载(const版本)
const T& operator[](int index) const {
return data[index];
}

// 获取数组大小
int size() const {
return N;
}

// 填充数组
void fill(T value) {
for (int i = 0; i < N; ++i) {
data[i] = value;
}
}

// 显示数组内容
void display() const {
std::cout << "Array elements: ";
for (int i = 0; i < N; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
};

// 10. 模板类 - 对(相同类型)
template<typename T>
class Pair {
private:
T first; // 第一个元素
T second; // 第二个元素

public:
// 构造函数
Pair(T a, T b) : first(a), second(b) {}

// 获取第一个元素
T getFirst() const {
return first;
}

// 获取第二个元素
T getSecond() const {
return second;
}

// 设置第一个元素
void setFirst(T value) {
first = value;
}

// 设置第二个元素
void setSecond(T value) {
second = value;
}

// 显示内容
void display() const {
std::cout << "Pair: (" << first << ", " << second << ")" << std::endl;
}
};

// 11. 模板类 - 对(不同类型)
template<typename T1, typename T2>
class Pair2 {
private:
T1 first; // 第一个元素(类型T1)
T2 second; // 第二个元素(类型T2)

public:
// 构造函数
Pair2(T1 a, T2 b) : first(a), second(b) {}

// 获取第一个元素
T1 getFirst() const {
return first;
}

// 获取第二个元素
T2 getSecond() const {
return second;
}

// 显示内容
void display() const {
std::cout << "Pair: (" << first << ", " << second << ")" << std::endl;
}
};

// 12. 模板类 - 智能指针(简化版)
template<typename T>
class SmartPointer {
private:
T* ptr; // 原始指针

public:
// 构造函数
SmartPointer(T* p = nullptr) : ptr(p) {}

// 析构函数
~SmartPointer() {
delete ptr;
}

// 解引用运算符重载
T& operator*() {
return *ptr;
}

// 箭头运算符重载
T* operator->() {
return ptr;
}

// 获取原始指针
T* get() const {
return ptr;
}
};

// 13. 模板类 - 链表节点
template<typename T>
class Node {
public:
T data; // 节点数据
Node* next; // 指向下一个节点的指针

// 构造函数
Node(T value) : data(value), next(nullptr) {}
};

// 14. 模板类 - 单链表
template<typename T>
class LinkedList {
private:
Node<T>* head; // 链表头节点

public:
// 构造函数
LinkedList() : head(nullptr) {}

// 析构函数
~LinkedList() {
Node<T>* current = head;
while (current) {
Node<T>* next = current->next;
delete current;
current = next;
}
}

// 添加节点到链表末尾
void add(T value) {
Node<T>* newNode = new Node<T>(value);
if (!head) {
head = newNode;
} else {
Node<T>* current = head;
while (current->next) {
current = current->next;
}
current->next = newNode;
}
}

// 显示链表内容
void display() const {
Node<T>* current = head;
std::cout << "LinkedList: ";
while (current) {
std::cout << current->data << " -> ";
current = current->next;
}
std::cout << "nullptr" << std::endl;
}
};

// 15. 模板特化 - 针对const char*类型的Box特化
template<>
class Box<const char*> {
private:
std::string value; // 使用std::string存储字符串

public:
// 构造函数
Box(const char* v) : value(v) {}

// 获取值
const char* getValue() const {
return value.c_str();
}

// 设置值
void setValue(const char* v) {
value = v;
}

// 显示内容
void display() const {
std::cout << "Box contains: " << value << std::endl;
}
};

int main() {
std::cout << "=== 1. 模板函数 ===" << std::endl;
std::cout << "最大值 of 10 and 20: " << maximum(10, 20) << std::endl;
std::cout << "最大值 of 3.14 and 2.71: " << maximum(3.14, 2.71) << std::endl;
std::cout << "最大值 of 'a' and 'z': " << maximum('a', 'z') << std::endl;

std::cout << "\n最小值 of 10 and 20: " << minimum(10, 20) << std::endl;
std::cout << "最小值 of 3.14 and 2.71: " << minimum(3.14, 2.71) << std::endl;

int x = 5, y = 10;
std::cout << "\n交换前: x = " << x << ", y = " << y << std::endl;
swapValues(x, y);
std::cout << "交换后: x = " << x << ", y = " << y << std::endl;

double a = 1.5, b = 2.5;
std::cout << "交换前: a = " << a << ", b = " << b << std::endl;
swapValues(a, b);
std::cout << "交换后: a = " << a << ", b = " << b << std::endl;

std::cout << "Add(3, 4) = " << add(3, 4) << std::endl;
std::cout << "Add(3.5, 4.5) = " << add(3.5, 4.5) << std::endl;
std::cout << "AddMixed(3, 4.5) = " << addMixed(3, 4.5) << std::endl;

// 测试数组求和函数
int intArray[] = {1, 2, 3, 4, 5};
double doubleArray[] = {1.1, 2.2, 3.3, 4.4};
std::cout << "\n数组求和: " << sumArray(intArray) << std::endl;
std::cout << "数组求和: " << sumArray(doubleArray) << std::endl;

std::cout << "\n=== 2. 模板类 Box ===" << std::endl;
Box<int> intBox(42);
intBox.display();

Box<double> doubleBox(3.14159);
doubleBox.display();

Box<std::string> stringBox("Hello Template!");
stringBox.display();

// 测试模板特化
Box<const char*> charBox("Specialized Template");
charBox.display();

std::cout << "\n=== 3. 模板类 Stack ===" << std::endl;
Stack<int> intStack(5);
intStack.push(10);
intStack.push(20);
intStack.push(30);

while (!intStack.isEmpty()) {
std::cout << "弹出: " << intStack.pop() << std::endl;
}

Stack<std::string> stringStack(3);
stringStack.push("First");
stringStack.push("Second");
stringStack.push("Third");

while (!stringStack.isEmpty()) {
std::cout << "弹出: " << stringStack.pop() << std::endl;
}

std::cout << "\n=== 4. 带非类型参数的模板类 Array ===" << std::endl;
Array<int, 5> intArrayObj;
for (int i = 0; i < intArrayObj.size(); ++i) {
intArrayObj[i] = i * 10;
}

intArrayObj.display();

// 测试fill方法
Array<double, 3> doubleArrayObj;
doubleArrayObj.fill(3.14);
doubleArrayObj.display();

std::cout << "\n=== 5. 模板类 Pair ===" << std::endl;
Pair<int> intPair(10, 20);
intPair.display();

Pair<double> doublePair(3.14, 2.71);
doublePair.display();

Pair2<std::string, int> mixedPair("Age", 25);
mixedPair.display();

Pair2<int, double> mixedPair2(100, 99.99);
mixedPair2.display();

std::cout << "\n=== 6. 模板类 SmartPointer ===" << std::endl;
SmartPointer<int> smartPtr(new int(100));
std::cout << "智能指针值: " << *smartPtr << std::endl;

SmartPointer<std::string> stringPtr(new std::string("Smart String"));
std::cout << "智能指针值: " << *stringPtr << std::endl;

std::cout << "\n=== 7. 模板类 LinkedList ===" << std::endl;
LinkedList<int> intList;
intList.add(10);
intList.add(20);
intList.add(30);
intList.display();

LinkedList<std::string> stringList;
stringList.add("Hello");
stringList.add("World");
stringList.display();

return 0;
}