目录
泛型编程
函数模板
函数模板的实例化
隐式类型实例化
显式类型实例化
匹配规则
类模板
非类型模版参数
模板的特化
模板的分离编译
泛型编程
void Swap(int& left, int& right) { int temp = left; left = right; right = temp; } void Swap(double& left, double& right) { double temp = left; left = right; right = temp; } void Swap(char& left, char& right) { char temp = left; left = right; right = temp; }在学习C语言的时候学习过交换的函数,这里用到C++的引用交换,但是可以看到如果对每一种类型都写一个交换的函数是特别的冗余,他们仅仅是类型不同,代码复用率低,每当有新的类型出现的时候就要写一个新的函数,为了解决这个问题就有了泛型编程。
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
函数模板
函数模板是代表了一类函数家族,家族的逻辑是一样的,但是他们的类型不一样,在函数传参的时候,函数模板会根据实参的类型产生特定的函数。
格式:template<typename T1, typename T2,......,typename Tn>
template<typename T> void Swap( T& left, T& right) { T temp = left; left = right; right = temp; }通过上面的模板函数,就可以调用不同类型的参数的函数,不需要单独实现特定类型的函数。
注意:typename是模板参数的关键字,template是定义模板的关键字,可以定义多个不同的typename,typename可以用class替代但是不可以用struct替代。
函数模板的实例化
隐式类型实例化
编译器可以根据实参的类型自动推演传给形参的类型,从而产生对应的函数。
#include <iostream> using namespace std; template <class T> T Add(const T& x, const T& y) { return x + y; } int main() { cout << Add(1.1,2.2) << endl;//double cout << Add(1, 2) << endl;//int return 0; }显式类型实例化
#include <iostream> using namespace std; template <class T> T Add(const T& x, const T& y) { return x + y; } int main() { /*cout << Add(1.1,2.2) << endl; cout << Add(1, 2) << endl;*/ int a = 10; int b = 3; cout<<Add<int>(a, b) << endl; cout<<Add(a, b) << endl; return 0; }匹配规则
#include <iostream> using namespace std; template <class T> T Add(const T& x, const T& y) { return x + y; } //template<class T1, class T2> //T1 Add(const T1& left, const T2& right) //{ //return left + right; //} template<class T> T* func1(int n) { return new T[n]; } int main() { int a1 = 10, a2 = 20; double d1 = 10.1, d2 = 20.2; Add(a1, a2); Add(d1, d2); cout << Add(a1, d1) << endl; //由于上述模板的参数都是一样的,所以该编译报错,除非使用注释的代码 // 推导实例化 cout << Add(a1, (int)d1) << endl; cout << Add((double)a1, d1) << endl; //也可以强制类型转化 // 显示实例化 cout << Add<int>(a1, d1) << endl; cout << Add<double>(a1, d1) << endl; cout << Add(a1, d1) << endl;//也可以不用<> double* p1 = func1<double>(10); return 0; }类模板
template<typename T> class Stack { public: Stack(int n = 4) :_array(new T[n]) ,_size(0) ,_capacity(n) {} ~Stack() { delete[] _array; _array = nullptr; _size = _capacity = 0; } void Push(const T& x); private: T* _array; size_t _capacity; size_t _size; }; template<class T>//声明的时候要加上template void Stack<T>::Push(const T& x) { if (_size == _capacity) { T* tmp = new T[_capacity * 2]; memcpy(tmp, _array, sizeof(T) * _size); delete[] _array; _array = tmp; _capacity *= 2; } _array[_size++] = x; } int main() { // 类模板都是显示实例化 Stack<int> st1; // int st1.Push(1); st1.Push(2); st1.Push(3); Stack<double> st2; // double st2.Push(1.1); st2.Push(1.1); st2.Push(1.1); Stack<double>* pst = new Stack<double>; //... delete pst; return 0; }注意:类模板成员函数在类外声明的时候要加template
函数模板实例化的时候
template<typename T> T Add(T a, T b) { return a + b; } // 使用时,编译器能自动推导类型 Add(1, 2); // 编译器自动推导 T = int Add(1.0, 2.0); // 编译器自动推导 T = double类模板实例化
template<typename T> class Stack { T* _data; int _top; }; // 使用类模板时,必须在 <> 中指定类型 Stack<int> st1; // Stack<int> 是类型 Stack<double> st2; // Stack<double> 是类型 Stack st3; // 错误!Stack 不是类型,不能直接使用总结:函数模板实例化的时候,编译器会自动推导,不需要担心他和其他函数的冲突,但是类模板实例化的时候必须要有<>,否则报错。
非类型模版参数
template<class T, size_t N = 10> class array { private: T _array[N]; // N 是编译期常量 size_t _size; }; array<int, 20> a1; // N = 20 array<double, 5> a2; // N = 5这个是定义了一个静态数组的类,如果不传参,默认的空间是10。
模板的特化
通用模板
template<class T1, class T2> class Data { public: Data() { cout << "Data<T1, T2>" << endl; } private: T1 _d1; T2 _d2; };全特化
template<> class Data<int, char> { public: Data() { cout << "Data<int, char>" << endl; } }; //调用的时候 Data<int, char> d2; // 走全特化直接指定什么类型才使用该函数,就是给他特权,单独写一个。
特点:
template<>(空的尖括号)两个模板参数全部确定:
int和char匹配优先级最高
偏特化
template<class T1> class Data<T1, double> { public: Data() { cout << "Data<T1, double>" << endl; } }; template<class T1> class Data<T1, char> { public: Data() { cout << "Data<T1, char>" << endl; } }; //调用 Data<int, double> d3; // 走 Data<T1, double> 偏特化 Data<char, double> d4; // 走 Data<T1, double> 偏特化(T1 = char) Data<char, char> d5; // Data<T1, char> 偏特化! template <typename T1, typename T2> class Data <T1&, T2&> { public: Data() { cout << "Data<T1&, T2&>" << endl; } }; //调用 Data<int&, char&> d8; // 走 Data<T1&, T2&> Data<int&, double&> d9; // 走 Data<T1&, T2&>只定义一个通用的类型,一个确定的类型
特点:
第一个参数保留为
T1(灵活)第二个参数固定为
double或char匹配优先级高于通用模板,低于全特化
引用+指针
template <typename T1, typename T2> class Data <T1&, T2*> { public: Data() { cout << "Data<T1&, T2*>" << endl; int a = 0; T1& x = a; // 如果 T1 = int,x 是 int&,绑定到 a T2* y = &a; // 如果 T2 = int,y 是 int*,指向 a T1 z = a; // 如果 T1 = int,z = a cout << typeid(x).name() << endl; cout << typeid(y).name() << endl; } void Push(const T1& x) // 如果 T1 = int,参数是 const int& {} }; //调用 Data<int&, int*> d10; 这行代码告诉编译器: 第一个参数是 int&(引用类型) 第二个参数是 int*(指针类型)T1本身永远是一个“普通类型”(比如int、char、double),它在T1&这个特化版本中,被组合成了一个“引用类型”(int&)。
模板的分离编译
// a.h template<class T> T Add(const T& left, const T& right); // a.cpp template<class T> T Add(const T& left, const T& right) { return left + right; } // main.cpp #include "a.h" int main() { Add(1, 2); // 链接错误!找不到 Add<int> 的定义 }原因:
a.cpp编译时,不知道Add会被int实例化,不会生成Add<int>的代码main.cpp编译时,看到Add的声明,但不知道定义在哪里链接时,找不到
Add<int>的实现 → 报错