一、函数模板
1.什么是函数模板?
函数模板简单来说就是一个模板,与函数参数的类型无关,是一个模子,不是真正的函数,实例化的函数会根据实参的类型自动推导类型。
2.函数模板格式
template<typename T1,typename T2...> 返回值类型 函数名(参数列表) {}
3.函数模板原理
函数模板是一个模板,并不是真正的函数,它是根据传递过来的实参的类型实例化一个具体的函数,相当于我们将重复的事情交给了编译器来操作。
比如说:
template<typename T> T Add(const T& a1, const T& a2) { return a1 + a2; } int main() { int a = 10, b = 20; double c = 3.14,d = 2.11; cout << Add(a, b) << endl; cout << Add(c, d) << endl; return 0; }
我们定义了一个加法函数的函数模板,来进行加法操作,函数模板会根据我们传递的实参的类型自动实例化出不同的Add函数,这些函数之间构成函数重载。
4.函数模板实例化
(1)隐式实例化
举一个简单的例子:
在我们定义的函数模板中,只给定一个模板参数类型,但是我们可能会有两个不同的实参类型。
template<typename T> T Add(const T& a1, const T& a2) { return a1 + a2; } int main() { int a = 10; double b = 20.3; cout << Add(a, b) << endl; return 0; }
对于只有一个类型的函数模板,却同时出现了两种不同类型的实参,编译器就无法确认到底用哪个实参类型实例化了。
解决办法:
int main() { int a = 10; double b = 20.3; cout << Add((double)a, b) << endl; cout << Add(a, (int)b) << endl; //可能存在精度丢失的情况 return 0; }
隐式类型转换,就可以解决编译器无法识别的情况。
(2)显示实例化
template<typename T> T Add(const T& a1, const T& a2) { return a1 + a2; } int main() { int a = 10; double b = 20.3; cout << Add(a, b) << endl; return 0; }
对于这个案例,还有一种解决方案:
int main() { int a = 10; double b = 20.3; cout << Add<int>(a, b) << endl; return 0; }
这样的方法叫做显式实例化,实际生活中,我们很少会遇到需要显式实例化的情况,不过对于下面的情况,就必须要显式实力化。
template<class T> T* Alloc(int n) { return new T[n]; } int main() { Alloc<double>(10); return 0; }
在这样的情况下,我们没有使用函数模板类型,所以仅仅传递实参n无法推导T的类型,这种情况下必须要使用显式实例化。
二.类模板
1.类模板定义格式
template<class T1, class T2, ..., class Tn> class 类模板名 { // 类内成员定义 };
2.类模板的实例化
注意:
普通类的类型和类名相同
模板类的类型和类名不同
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可。
类模板名字不是真正的类,而实例化的结果才是真正的类。
比如:
// string类名,string<int>才是类型 string<int> s1; string<double> s2;
1.不管是类模板还是函数模板,其作用范围就是紧跟着的类/函数。
也就是看{}
2.类模板中函数放在类外进行定义时,需要加模板参数列表
比如:
template<typename T> class Stack { public: Stack(size_t capacity = 3); void Push(const T& data); // 其他方法... ~Stack() { if (_array) { delete[]_array; _capacity = _size = 0; } } private: T* _array; int _capacity; int _size; }; //缺省参数不能给在函数定义,只能在声明给缺省值 //模板的作用域就是专门给一个函数或者一个类用的 //可以看{}的作用范围是那里,模板的作用范围就是哪里。 template<typename T> Stack<T>::Stack(size_t capacity) { _array = new T[capacity]; _capacity = capacity; _size = 0; } template<typename T> void Stack<T>::Push(const T& data) { // CheckCapacity(); _array[_size] = data; _size++; }
函数在类外面进行定义时,需要加类模板的参数列表。
注意:不建议模板实例化出来的函数的声明和定义分离。
注意:不建议模板实例化出来的函数的声明和定义分离。
注意:不建议模板实例化出来的函数的声明和定义分离。
上面的例子仅仅是为了演示。
总结
本文讲述了函数模板和类模板的相关问题。