一文详解C++模板和泛型编程
简介
C++模板是实现泛型编程的基础。泛型编程是一种编程范式,通过参数化来实现算法的一种方式。C++模板可以用来定义不特定类型的函数、类等,可以减少代码的重复编写,提高代码的可维护性和可复用性。
模板的定义和使用
函数模板
函数模板可以用来定义可以适用于多种类型的函数。函数模板需要使用关键字template
定义,后面跟尖括号<>
中的类型参数。
template<typename T>
void mySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
上面定义了一个函数模板mySwap
用于交换两个元素的值。T
是类型参数,表示在调用函数的时候会具体化为某一种类型。函数模板调用时可以指定T
的类型,也可以让编译器根据函数实参的类型自动推断出T
的类型。
int a = 1, b = 2;
mySwap(a, b); // 实例化出 void mySwap<int>(int&, int&)
类模板
类模板可以用于定义适用于多种类型的类。类模板定义和函数模板定义相似,也需要使用template
关键字来定义,尖括号中指定类型参数。
template<typename T>
class Stack {
private:
int top;
T stack[100];
public:
Stack() : top(-1) {}
void push(const T& item) {
stack[++top] = item;
}
T pop() {
return stack[top--];
}
};
上面的代码定义了一个模板类Stack
,可以适用于各种类型。T
是类型参数,表示在使用时会被实际的类型替换。类模板中可以包含成员变量、成员函数等。使用类模板时需要指定类型参数,也可以让编译器根据类对象的成员类型自动推断出类型参数。
Stack<int> s;
s.push(1);
s.push(2);
int a = s.pop(); // a = 2
模板特化
模板特化是对通用模板进行特殊化处理,以便能够处理某些特定情况。模板特化可以分为两种,全特化和偏特化。
全特化
全特化是指将模板参数完全具体化,成为一个普通的函数或类定义。全特化时,需要在尖括号中指定具体的类型参数。
template<typename T>
class Compare {
public:
bool operator()(const T& a, const T& b) const {
return a < b;
}
};
template<>
class Compare<const char*> {
public:
bool operator()(const char* a, const char* b) const {
return strcmp(a, b) < 0;
}
};
上面的代码定义了模板类Compare
,用于比较两个值的大小。当类型参数为const char*
时,进行特化处理,特化版本提供了比较字符串的实现。
Compare<int> cmp;
bool res1 = cmp(1, 2); // true
Compare<const char*> s_cmp;
bool res2 = s_cmp("hello", "world"); // false
偏特化
偏特化是指将模板参数部分具体化,成为一个新的模板定义。偏特化时,需要在尖括号中指定一些或全部的类型参数。
template<typename T1, typename T2>
struct is_same {
static const bool value = false;
};
template<typename T>
struct is_same<T, T> {
static const bool value = true;
};
上面的代码定义了一个模板类is_same
,用于比较两个类型是否相同。当类型参数相同时,进行偏特化处理,偏特化版本提供了true
的值。
bool res1 = is_same<int, float>::value; // false
bool res2 = is_same<int, int>::value; // true
总结
- C++模板是泛型编程的基础。
- 函数模板和类模板可以适用于多种类型。
- 使用类型参数和自动推断,可以使代码更加灵活、可维护、可复用。
- 模板特化可以针对一些特定情况,提供更优的实现。
- 全特化和偏特化是两种特化方式,可以针对具体情况进行处理。
以上是“一文详解C++模板和泛型编程”的完整攻略。接下来给出两个示例说明。
示例1:使用函数模板实现多种类型参数的加法
#include <iostream>
using namespace std;
template<typename T>
T add(T a, T b) {
return a + b;
}
int main() {
int x = 1, y = 2;
float a = 1.2, b = 3.4;
cout << add(x, y) << endl;
cout << add(a, b) << endl;
return 0;
}
输出:
3
4.6
上面的代码中,使用了函数模板add
,可以适用于int
和float
两种类型,调用的时候会将类型参数实例化为具体类型。
示例2:使用类模板实现一个指针类型的栈容器
#include <iostream>
using namespace std;
template<typename T>
class Stack {
private:
int top;
T* stack;
int capacity;
public:
Stack(int size = 100) : top(-1), capacity(size) {
stack = new T[size];
}
~Stack() {
delete[] stack;
}
void push(const T& item) {
stack[++top] = item;
}
T pop() {
return stack[top--];
}
};
int main() {
Stack<int*> s(3);
int x = 1, y = 2, z = 3;
s.push(&x);
s.push(&y);
s.push(&z);
while(s.pop()) {
cout << *s.pop() << endl;
}
return 0;
}
输出:
3
2
1
上面的代码定义了一个类模板Stack
,用于存储指针类型。在主函数中,实例化了一个Stack<int*>
对象s
,并将几个指针推入栈中,最后弹出并输出所有指针所指向的值。
以上是两个示例,介绍了函数模板和类模板的使用。需要注意的是,在特化的时候,特化版本的实现需要和原模板的接口返回类型、参数列表都一致。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一文详解C++模板和泛型编程 - Python技术站