模板是一种通用的描述机制,使用模板允许使用通用类型来定义函数或类。在使用时,通用类型可被具体的类型,如 int、double 甚至是用户自定义的类型来代替。通过模板,开发者可以编写不同数据类型的相同操作,而无需为每种类型重复编写相似的代码。这不仅减少了代码冗余,提高了开发效率,还增强了类型安全性,因为模板在编译时进行类型检查,避免了运行时错误。
模板引入一种全新的编程思维方式,称为“泛型编程”或“通用编程”。
引例,想要实现能够处理各种类型参数的加法函数
以前我们需要进行函数重载(函数名相同,函数参数不同)
xxxxxxxxxx
191int add(int x, int y)
2{
3return x + y;
4}
5
6double add(double x, double y)
7{
8return x + y;
9}
10
11long add(long x, long y)
12{
13return x + y;
14}
15
16string add(string x, string y)
17{
18return x + y;
19}
在使用时看起来只需要调用add函数,传入不同类型的参数就可以进行相应的计算了,很方便。
但是程序员为了这种方便,实际上要定义很多个函数来处理各种情况的参数。
模板(将数据类型作为参数)
上面的问题用函数模板的方式就可以轻松解决:
xxxxxxxxxx
151//希望将类型参数化
2//使用class关键字或typename关键字都可以
3template <class T>
4T add(T x, T y)
5{
6return x + y;
7}
8
9int main(void){
10// 处理int数据
11cout << add(1,2) << endl;
12// 处理double数据
13cout << add(1.2,3.4) << endl;
14return 0;
15}
函数模板的优点:
不需要程序员定义出大量的函数,在调用时实例化出对应的模板函数,更“智能”
模板发生的时机是在编译时
模板本质上就是一个代码生成器,它的作用就是让编译器根据实际调用来生成代码。
编译器去处理时,实际上由函数模板生成了多个模板函数,或者由类模板生成了多个模板类。
模板作为实现代码重用机制的一种工具,它可以实现类型参数化,也就是把类型定义为参数,从而实现了真正的代码可重用性。
模板可以分为两类,
一个是函数模版,
另外一个是类模板。
通过参数实例化定义出具体的函数或类,称为模板函数或模板类。
函数模板是C++中实现泛型编程的基础工具,它允许我们编写与类型无关的函数,编译器会根据调用时提供的参数类型自动生成相应的函数实例。
函数模板定义了一个函数的模式,其中一个或多个参数的类型用模板参数表示。当调用函数模板时,编译器根据实际参数的类型推导出模板参数,并生成对应的函数代码。
xxxxxxxxxx
221// 基本函数模板语法
2template<typename T>
3T max(const T& a, const T& b) {
4 return (a > b) ? a : b;
5}
6
7// 或者使用class关键字(与typename等价)
8template<class T>
9T min(const T& a, const T& b) {
10 return (a < b) ? a : b;
11}
12
13// 使用示例
14void basicExample() {
15 int x = 10, y = 20;
16 double dx = 3.14, dy = 2.71;
17 string s1 = "apple", s2 = "banana";
18
19 cout << max(x, y) << endl; // T = int
20 cout << max(dx, dy) << endl; // T = double
21 cout << max(s1, s2) << endl; // T = string
22}
自动类型推导
xxxxxxxxxx
171template<typename T>
2void print(const T& value) {
3 cout << "Value: " << value << ", Type: " << typeid(T).name() << endl;
4}
5
6void typeDeductionDemo() {
7 print(42); // T推导为int
8 print(3.14); // T推导为double
9 print("Hello"); // T推导为const char*
10 print(string("World")); // T推导为string
11
12 auto x = 42;
13 print(x); // T推导为int
14
15 const int y = 100;
16 print(y); // T推导为int(const被忽略)
17}
显式模板参数
xxxxxxxxxx
251template<typename T>
2T convert(const string& str) {
3 if constexpr (is_same_v<T, int>) {
4 return stoi(str);
5 } else if constexpr (is_same_v<T, double>) {
6 return stod(str);
7 } else if constexpr (is_same_v<T, float>) {
8 return stof(str);
9 }
10 return T{};
11}
12
13void explicitTemplateDemo() {
14 string numStr = "123";
15 string floatStr = "3.14";
16
17 // 显式指定模板参数
18 int i = convert<int>(numStr);
19 double d = convert<double>(floatStr);
20 float f = convert<float>(floatStr);
21
22 cout << "Int: " << i << endl;
23 cout << "Double: " << d << endl;
24 cout << "Float: " << f << endl;
25}
多类型参数
xxxxxxxxxx
231template<typename T1, typename T2>
2auto add(const T1& a, const T2& b) -> decltype(a + b) {
3 return a + b;
4}
5
6// C++14简化版本
7template<typename T1, typename T2>
8auto multiply(const T1& a, const T2& b) {
9 return a * b;
10}
11
12// 指定返回类型
13template<typename T1, typename T2, typename ReturnType = T1>
14ReturnType divide(const T1& a, const T2& b) {
15 return static_cast<ReturnType>(a) / static_cast<ReturnType>(b);
16}
17
18void multipleParamsDemo() {
19 cout << add(5, 3.14) << endl; // int + double = double
20 cout << multiply(2, 3.5f) << endl; // int * float = float
21 cout << divide(10, 3) << endl; // int / int = int
22 cout << divide<int, int, double>(10, 3) << endl; // 强制返回double
23}
非类型模板参数
xxxxxxxxxx
281template<typename T, int Size>
2void printArray(const T (&arr)[Size]) {
3 cout << "Array of " << Size << " elements: ";
4 for (int i = 0; i < Size; ++i) {
5 cout << arr[i] << " ";
6 }
7 cout << endl;
8}
9
10template<int N>
11constexpr int factorial() {
12 if constexpr (N <= 1) {
13 return 1;
14 } else {
15 return N * factorial<N-1>();
16 }
17}
18
19void nonTypeParamDemo() {
20 int arr1[] = {1, 2, 3, 4, 5};
21 double arr2[] = {1.1, 2.2, 3.3};
22
23 printArray(arr1); // Size = 5
24 printArray(arr2); // Size = 3
25
26 constexpr int fact5 = factorial<5>();
27 cout << "5! = " << fact5 << endl;
28}
xxxxxxxxxx
241// 通用模板
2template<typename T>
3void process(const T& value) {
4 cout << "Processing generic type: " << value << endl;
5}
6
7// 针对const char*的全特化
8template<>
9void process<const char*>(const char* const& value) {
10 cout << "Processing C-string: \"" << value << "\"" << endl;
11}
12
13// 针对bool的全特化
14template<>
15void process<bool>(const bool& value) {
16 cout << "Processing boolean: " << (value ? "true" : "false") << endl;
17}
18
19void specializationDemo() {
20 process(42); // 通用模板
21 process(3.14); // 通用模板
22 process("Hello"); // const char*特化
23 process(true); // bool特化
24}
xxxxxxxxxx
331// 1. 普通函数
2void print(int value) {
3 cout << "Regular function: " << value << endl;
4}
5
6// 2. 函数模板
7template<typename T>
8void print(const T& value) {
9 cout << "Template function: " << value << endl;
10}
11
12// 3. 函数模板重载
13template<typename T>
14void print(T* ptr) {
15 cout << "Template for pointer: " << *ptr << endl;
16}
17
18// 4. 特化的函数模板
19template<>
20void print<double>(const double& value) {
21 cout << "Specialized for double: " << value << endl;
22}
23
24void overloadDemo() {
25 int x = 42;
26 double d = 3.14;
27 string s = "Hello";
28
29 print(x); // 调用普通函数(最优匹配)
30 print(d); // 调用特化模板
31 print(s); // 调用通用模板
32 print(&x); // 调用指针模板
33}
基本变参模板
xxxxxxxxxx
281// 递归终止版本
2void print() {
3 cout << endl;
4}
5
6// 变参模板版本
7template<typename T, typename... Args>
8void print(const T& first, const Args&... args) {
9 cout << first;
10 if (sizeof...(args) > 0) {
11 cout << ", ";
12 print(args...);
13 } else {
14 cout << endl;
15 }
16}
17
18// 使用折叠表达式(C++17)
19template<typename... Args>
20void print_fold(const Args&... args) {
21 ((cout << args << " "), ...);
22 cout << endl;
23}
24
25void variadicDemo() {
26 print(1, 2.5, "Hello", 'A', true);
27 print_fold("Fold:", 1, 2, 3, 4, 5);
28}
变参模板应用
xxxxxxxxxx
391// 通用的make_unique实现
2template<typename T, typename... Args>
3unique_ptr<T> make_unique_custom(Args&&... args) {
4 return unique_ptr<T>(new T(forward<Args>(args)...));
5}
6
7// 变参求和
8template<typename T>
9T sum(const T& value) {
10 return value;
11}
12
13template<typename T, typename... Args>
14T sum(const T& first, const Args&... args) {
15 return first + sum(args...);
16}
17
18// C++17折叠表达式版本
19template<typename... Args>
20auto sum_fold(const Args&... args) {
21 return (args + ...);
22}
23
24class TestClass {
25public:
26 int x, y;
27 TestClass(int a, int b) : x(a), y(b) {
28 cout << "TestClass(" << a << ", " << b << ")" << endl;
29 }
30};
31
32void variadicApplicationDemo() {
33 // 使用变参模板创建对象
34 auto ptr = make_unique_custom<TestClass>(10, 20);
35
36 // 变参求和
37 cout << "Sum: " << sum(1, 2, 3, 4, 5) << endl;
38 cout << "Sum fold: " << sum_fold(1, 2, 3, 4, 5) << endl;
39}
xxxxxxxxxx
621// 泛型查找算法
2template<typename Iterator, typename T>
3Iterator find_element(Iterator first, Iterator last, const T& value) {
4 while (first != last) {
5 if (*first == value) {
6 return first;
7 }
8 ++first;
9 }
10 return last;
11}
12
13// 泛型谓词查找
14template<typename Iterator, typename Predicate>
15Iterator find_if_custom(Iterator first, Iterator last, Predicate pred) {
16 while (first != last) {
17 if (pred(*first)) {
18 return first;
19 }
20 ++first;
21 }
22 return last;
23}
24
25// 泛型变换算法
26template<typename InputIt, typename OutputIt, typename UnaryOp>
27OutputIt transform_custom(InputIt first, InputIt last, OutputIt result, UnaryOp op) {
28 while (first != last) {
29 *result = op(*first);
30 ++first;
31 ++result;
32 }
33 return result;
34}
35
36void algorithmDemo() {
37 vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
38
39 // 查找元素
40 auto it = find_element(vec.begin(), vec.end(), 5);
41 if (it != vec.end()) {
42 cout << "Found: " << *it << endl;
43 }
44
45 // 查找偶数
46 auto even_it = find_if_custom(vec.begin(), vec.end(),
47 [](int x) { return x % 2 == 0; });
48 if (even_it != vec.end()) {
49 cout << "First even: " << *even_it << endl;
50 }
51
52 // 变换:每个元素乘以2
53 vector<int> result(vec.size());
54 transform_custom(vec.begin(), vec.end(), result.begin(),
55 [](int x) { return x * 2; });
56
57 cout << "Transformed: ";
58 for (int x : result) {
59 cout << x << " ";
60 }
61 cout << endl;
62}
成员函数模板是定义在类内部的模板函数,可以接受模板参数,使得同一个函数能够处理不同类型的数据。
xxxxxxxxxx
141class MyClass {
2public:
3 // 成员函数模板
4 template<typename T>
5 void func(T value) {
6 // 函数实现
7 }
8
9 // 带返回值的成员函数模板
10 template<typename T>
11 T getValue(T input) {
12 return input;
13 }
14};
xxxxxxxxxx
641
2
3
4using namespace std;
5
6class Container {
7private:
8 vector<int> data;
9
10public:
11 Container() : data{1, 2, 3, 4, 5} {}
12
13 // 成员函数模板:打印任意类型的值
14 template<typename T>
15 void print(const T& value) {
16 cout << "打印值: " << value << endl;
17 }
18
19 // 成员函数模板:转换并返回
20 template<typename T>
21 T convert(int index) {
22 if (index >= 0 && index < data.size()) {
23 return static_cast<T>(data[index]);
24 }
25 return T{}; // 返回默认值
26 }
27
28 // 成员函数模板:比较两个值
29 template<typename T>
30 bool compare(const T& a, const T& b) {
31 return a == b;
32 }
33
34 // 成员函数模板:添加元素到容器
35 template<typename T>
36 void addConverted(const T& value) {
37 data.push_back(static_cast<int>(value));
38 }
39};
40
41int main() {
42 Container container;
43
44 // 使用成员函数模板
45 container.print(42); // T = int
46 container.print(3.14); // T = double
47 container.print("Hello"); // T = const char*
48 container.print(string("World")); // T = string
49
50 // 类型转换
51 double d = container.convert<double>(0); // 将int转换为double
52 float f = container.convert<float>(1); // 将int转换为float
53 cout << "转换结果: " << d << ", " << f << endl;
54
55 // 比较操作
56 cout << "比较结果: " << container.compare(10, 10) << endl;
57 cout << "比较结果: " << container.compare(3.14, 2.71) << endl;
58
59 // 添加转换后的元素
60 container.addConverted(3.14);
61 container.addConverted('A'); // ASCII值
62
63 return 0;
64}
Note
实例化时机:成员函数模板只有在被调用时才会实例化
类型推导:编译器可以自动推导模板参数类型
特化:可以为特定类型提供特化版本
继承:成员函数模板可以被继承,但不能被虚化
在一个模块中定义多个通用模板的写法应该谨慎使用;
调用函数模板时尽量使用隐式调用,让编译器推导出类型;
无法使用隐式调用的场景只指定必须要指定的类型;
需要使用特化模板的场景就根据特化模板将类型指定清楚。
类模板是一个类的蓝图,可以根据不同的类型参数生成具体的类。它使得同一个类可以处理不同的数据类型,而不需要为每种类型重复编写代码。
xxxxxxxxxx
101template<typename T>
2class ClassName {
3private:
4 T data;
5
6public:
7 ClassName(const T& value) : data(value) {}
8 T getValue() const { return data; }
9 void setValue(const T& value) { data = value; }
10};
xxxxxxxxxx
431
2using namespace std;
3
4// 基本的类模板
5template<typename T>
6class Box {
7private:
8 T content;
9
10public:
11 // 构造函数
12 Box(const T& item) : content(item) {
13 cout << "创建Box,内容: " << content << endl;
14 }
15
16 // 获取内容
17 T getContent() const {
18 return content;
19 }
20
21 // 设置内容
22 void setContent(const T& item) {
23 content = item;
24 }
25
26 // 显示内容
27 void display() const {
28 cout << "Box内容: " << content << endl;
29 }
30};
31
32int main() {
33 // 使用不同类型实例化类模板
34 Box<int> intBox(42);
35 Box<double> doubleBox(3.14);
36 Box<string> stringBox("Hello World");
37
38 intBox.display();
39 doubleBox.display();
40 stringBox.display();
41
42 return 0;
43}
多个模板参数
xxxxxxxxxx
331
2using namespace std;
3
4// 多个模板参数的类模板
5template<typename T, typename U>
6class Pair {
7private:
8 T first;
9 U second;
10
11public:
12 Pair(const T& f, const U& s) : first(f), second(s) {}
13
14 T getFirst() const { return first; }
15 U getSecond() const { return second; }
16
17 void setFirst(const T& f) { first = f; }
18 void setSecond(const U& s) { second = s; }
19
20 void display() const {
21 cout << "Pair: (" << first << ", " << second << ")" << endl;
22 }
23};
24
25int main() {
26 Pair<int, string> p1(1, "One");
27 Pair<double, char> p2(3.14, 'A');
28
29 p1.display();
30 p2.display();
31
32 return 0;
33}
带默认参数的类模板
xxxxxxxxxx
621
2
3using namespace std;
4
5// 带默认模板参数
6template<typename T, int Size = 10>
7class Array {
8private:
9 T data[Size];
10 int currentSize;
11
12public:
13 Array() : currentSize(0) {}
14
15 bool add(const T& item) {
16 if (currentSize < Size) {
17 data[currentSize++] = item;
18 return true;
19 }
20 return false;
21 }
22
23 T get(int index) const {
24 if (index >= 0 && index < currentSize) {
25 return data[index];
26 }
27 throw out_of_range("索引超出范围");
28 }
29
30 int size() const { return currentSize; }
31 int capacity() const { return Size; }
32
33 void display() const {
34 cout << "Array [";
35 for (int i = 0; i < currentSize; ++i) {
36 cout << data[i];
37 if (i < currentSize - 1) cout << ", ";
38 }
39 cout << "]" << endl;
40 }
41};
42
43int main() {
44 Array<int> arr1; // 使用默认大小10
45 Array<string, 5> arr2; // 指定大小为5
46
47 // 添加元素
48 arr1.add(1);
49 arr1.add(2);
50 arr1.add(3);
51
52 arr2.add("Hello");
53 arr2.add("World");
54
55 arr1.display();
56 arr2.display();
57
58 cout << "arr1容量: " << arr1.capacity() << ", 大小: " << arr1.size() << endl;
59 cout << "arr2容量: " << arr2.capacity() << ", 大小: " << arr2.size() << endl;
60
61 return 0;
62}
xxxxxxxxxx
461
2using namespace std;
3
4// 通用类模板
5template<typename T>
6class Calculator {
7public:
8 T add(T a, T b) {
9 cout << "通用加法" << endl;
10 return a + b;
11 }
12
13 T multiply(T a, T b) {
14 cout << "通用乘法" << endl;
15 return a * b;
16 }
17};
18
19// 针对string类型的完全特化
20template<>
21class Calculator<string> {
22public:
23 string add(string a, string b) {
24 cout << "字符串连接" << endl;
25 return a + b;
26 }
27
28 string multiply(string a, string b) {
29 cout << "字符串重复" << endl;
30 string result;
31 for (char c : a) {
32 result += string(1, c) + b;
33 }
34 return result;
35 }
36};
37
38int main() {
39 Calculator<int> intCalc;
40 Calculator<string> stringCalc;
41
42 cout << intCalc.add(3, 4) << endl;
43 cout << stringCalc.add("Hello", "World") << endl;
44
45 return 0;
46}
xxxxxxxxxx
411
2using namespace std;
3
4// 通用类模板
5template<typename T, typename U>
6class Container {
7public:
8 void info() {
9 cout << "通用容器: T和U是不同类型" << endl;
10 }
11};
12
13// 偏特化:当T和U是同一类型时
14template<typename T>
15class Container<T, T> {
16public:
17 void info() {
18 cout << "偏特化容器: T和U是相同类型" << endl;
19 }
20};
21
22// 偏特化:当U是指针类型时
23template<typename T, typename U>
24class Container<T, U*> {
25public:
26 void info() {
27 cout << "偏特化容器: U是指针类型" << endl;
28 }
29};
30
31int main() {
32 Container<int, double> c1; // 使用通用模板
33 Container<int, int> c2; // 使用偏特化(相同类型)
34 Container<int, double*> c3; // 使用偏特化(指针类型)
35
36 c1.info();
37 c2.info();
38 c3.info();
39
40 return 0;
41}
xxxxxxxxxx
1011
2using namespace std;
3
4template<typename T>
5class SmartPtr {
6private:
7 T* ptr;
8 int* refCount;
9
10public:
11 // 构造函数
12 explicit SmartPtr(T* p = nullptr) : ptr(p), refCount(new int(1)) {
13 cout << "SmartPtr构造,引用计数: " << *refCount << endl;
14 }
15
16 // 拷贝构造函数
17 SmartPtr(const SmartPtr& other) : ptr(other.ptr), refCount(other.refCount) {
18 ++(*refCount);
19 cout << "SmartPtr拷贝构造,引用计数: " << *refCount << endl;
20 }
21
22 // 赋值操作符
23 SmartPtr& operator=(const SmartPtr& other) {
24 if (this != &other) {
25 release();
26 ptr = other.ptr;
27 refCount = other.refCount;
28 ++(*refCount);
29 cout << "SmartPtr赋值,引用计数: " << *refCount << endl;
30 }
31 return *this;
32 }
33
34 // 析构函数
35 ~SmartPtr() {
36 release();
37 }
38
39 // 解引用操作符
40 T& operator*() const {
41 return *ptr;
42 }
43
44 // 箭头操作符
45 T* operator->() const {
46 return ptr;
47 }
48
49 // 获取原始指针
50 T* get() const {
51 return ptr;
52 }
53
54 // 获取引用计数
55 int getRefCount() const {
56 return refCount ? *refCount : 0;
57 }
58
59private:
60 void release() {
61 if (refCount && --(*refCount) == 0) {
62 delete ptr;
63 delete refCount;
64 cout << "SmartPtr释放资源" << endl;
65 }
66 }
67};
68
69class TestClass {
70public:
71 int value;
72 TestClass(int v) : value(v) {
73 cout << "TestClass构造: " << value << endl;
74 }
75 ~TestClass() {
76 cout << "TestClass析构: " << value << endl;
77 }
78 void display() {
79 cout << "TestClass值: " << value << endl;
80 }
81};
82
83int main() {
84 {
85 SmartPtr<TestClass> ptr1(new TestClass(42));
86 cout << "引用计数: " << ptr1.getRefCount() << endl;
87
88 {
89 SmartPtr<TestClass> ptr2 = ptr1;
90 cout << "引用计数: " << ptr1.getRefCount() << endl;
91
92 ptr2->display();
93 (*ptr2).display();
94 }
95
96 cout << "ptr2销毁后引用计数: " << ptr1.getRefCount() << endl;
97 }
98
99 cout << "所有智能指针销毁" << endl;
100 return 0;
101}
xxxxxxxxxx
561
2using namespace std;
3
4// 基类模板
5template<typename T>
6class Base {
7protected:
8 T data;
9
10public:
11 Base(const T& value) : data(value) {}
12
13 virtual void display() const {
14 cout << "Base: " << data << endl;
15 }
16
17 virtual ~Base() = default;
18};
19
20// 派生类模板
21template<typename T>
22class Derived : public Base<T> {
23private:
24 T extraData;
25
26public:
27 Derived(const T& value, const T& extra)
28 : Base<T>(value), extraData(extra) {}
29
30 void display() const override {
31 cout << "Derived: " << this->data << ", Extra: " << extraData << endl;
32 }
33};
34
35// 从模板类派生的非模板类
36class IntDerived : public Base<int> {
37public:
38 IntDerived(int value) : Base<int>(value) {}
39
40 void display() const override {
41 cout << "IntDerived: " << data << endl;
42 }
43};
44
45int main() {
46 Base<int>* ptr1 = new Derived<int>(10, 20);
47 Base<int>* ptr2 = new IntDerived(30);
48
49 ptr1->display();
50 ptr2->display();
51
52 delete ptr1;
53 delete ptr2;
54
55 return 0;
56}
xxxxxxxxxx
621
2using namespace std;
3
4template<typename T>
5class Matrix;
6
7// 友元函数模板声明
8template<typename T>
9Matrix<T> operator+(const Matrix<T>& a, const Matrix<T>& b);
10
11template<typename T>
12class Matrix {
13private:
14 T data[2][2];
15
16public:
17 Matrix() {
18 for (int i = 0; i < 2; ++i) {
19 for (int j = 0; j < 2; ++j) {
20 data[i][j] = T{};
21 }
22 }
23 }
24
25 Matrix(T a, T b, T c, T d) {
26 data[0][0] = a; data[0][1] = b;
27 data[1][0] = c; data[1][1] = d;
28 }
29
30 // 友元函数
31 friend Matrix<T> operator+<T>(const Matrix<T>& a, const Matrix<T>& b);
32
33 // 友元输出函数
34 friend ostream& operator<<(ostream& os, const Matrix<T>& m) {
35 os << "[" << m.data[0][0] << " " << m.data[0][1] << "]\n";
36 os << "[" << m.data[1][0] << " " << m.data[1][1] << "]";
37 return os;
38 }
39};
40
41// 友元函数实现
42template<typename T>
43Matrix<T> operator+(const Matrix<T>& a, const Matrix<T>& b) {
44 Matrix<T> result;
45 for (int i = 0; i < 2; ++i) {
46 for (int j = 0; j < 2; ++j) {
47 result.data[i][j] = a.data[i][j] + b.data[i][j];
48 }
49 }
50 return result;
51}
52
53int main() {
54 Matrix<int> m1(1, 2, 3, 4);
55 Matrix<int> m2(5, 6, 7, 8);
56
57 cout << "矩阵1:\n" << m1 << endl;
58 cout << "矩阵2:\n" << m2 << endl;
59 cout << "相加结果:\n" << (m1 + m2) << endl;
60
61 return 0;
62}