一、函数模板
1、函数模板根据调用,自己推导模板参数的类型,实例化出对应的函数(自定义类型也可以)
#include<iostream>
#include<string>
using namespace std;
//泛型编程
//函数模板
//template<class Tp>
template<typename T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
template<typename T1, typename T2>
T1 Func(const T1& x, const T2& y)
{
cout << x << " " << y << endl;
return x;
}
// 函数模板实例化生成具体函数
// 函数模板根据调用,自己推导模板参数的类型,实例化出对应的函数(自定义类型也可以)
int main()
{
int a = 0, b = 1;
Swap(a, b);
double c = 1.1, d = 2.2;
Swap(c, d);
Func(1, 2);
Func(1, 2.2);
return 0;
}
2、通过实参传递的类型推演T的类型,可能会推导歧义
解决方法:显示实例化:Add<int>()
(有些函数无法自动推,只能显示实体化)
#include<iostream>
#include<string>
using namespace std;
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
template<class T>
T* Alloc(int n)
{
return new T[n];
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.1, d2 = 20.2;
// 实参传递的类型,推演T的类型
cout << Add(a1, a2) << endl;
cout << Add(d1, d2) << 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;
// 有些函数无法自动推,只能显示实例化
double* p1 = Alloc<double>(10);
return 0;
}
3、注意:
普通类,类名和类型是一样
类模板,类名和类型不一样
类名:Stack
类型:Stack<T>
#include<iostream>
#include<string>
using namespace std;
// 类模板
template<class T>
class Stack//类名
{
public:
//类里定义
Stack(size_t capacity = 3);
void Push(const T& data);
~Stack()
{
if (_array)
{
free(_array);
_array = NULL;
_capacity = 0;
_size = 0;
}
}
private:
T* _array;
int _capacity;
int _size;
};
//类型:Stack<T>
//类外声明
template<class T>
Stack<T>::Stack(size_t capacity)
{
_array = new T[capacity];
_capacity = capacity;
_size = 0;
}
template<class T>
void Stack<T>::Push(const T& data)
{
_array[_size] = data;
_size++;
}
显然,template的作用范围是模板下面第一个类/函数。类模板的成员函数是函数模板.
而用类模板实现栈时,需类里定义,类外声明(模板参数也要声明)
(不分离也可以,就是难看概况)
二、类模板、容器与仿函数
1、模板的三种用法:控制类型、控制适配器模式、控制仿函数
2、非类型模板参数:必须是整形常量
// 静态栈
// 非类型模板参数必须是整形常量
template<class T, size_t N>
class Stack
{
T _a[N];
int _top;
};
三、模板的特化(效果跟实例化出函数重载一样)
函数模板特化:
//仿函数
template<class T>
bool Less(T left, T right)
{
return left < right;
}
//函数模板的特化
template<>
bool Less<int*>(int* left, int* right)
{
return *left < *right;
}
bool Less(int* left, int* right)
{
return *left < *right;
}
template<class T>
bool Less(T* left, T* right)
{
return *left < *right;
}
类模板的全特化和偏特化:
//类
template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
// 针对int double要进行特殊处理
// 全特化
template<>
class Data<int, double>
{
public:
Data() { cout << "Data<int,double>" << endl; }
private:
};
// 偏特化 : 特化部分参数
template<class T1>
class Data<T1, double>
{
public:
Data() { cout << "Data<T1, double>" << endl; }
private:
};
// 偏特化 : 可能是对某些类型的进一步限制
template<class T1, class T2>
class Data<T1*, T2*>
{
public:
Data() { cout << "Data<T1*, T2*>" << endl; }
private:
};
template<class T1, class T2>
class Data<T1&, T2&>
{
public:
Data() { cout << "Data<T1&, T2&>" << endl; }
private:
};
四、模板的分离编译
复习:编译链接过程
Stack.h Stack.cpp Test.cpp
预处理:头文件展开/宏替换/条件编译/去掉注释
Stack.i Test.i
编译:检查语法,生成汇编代码
Stack.s Test.s
汇编:汇编代码转换成机器码(二进制)
Stack.o Test.o 符号表(存函数地址)
链接:可执行程序:xxx.exe/a.out
编译:声明(承诺)
编译:定义(直接兑现)
链接:找到定义(兑现承诺)
链接错误解决方式:显示实例化
temlate
class stack<int>;
五、总结
优点:
1、模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
2. 增强了代码的灵活性。(适配器/仿函数)
缺陷:
1、模板会导致代码膨胀问题,也会导致编译时间变长
2、出现模板编译错误时,错误信息非常凌乱,不易定位错误