C++模板理解
重新梳理一遍模板的知识
函数模板
函数模板是通用的函数描述,使用泛型来定义函数,泛型可以用具体的类型替换。将类型作为参数传递给模板。
例如建立一个交换模板:
template <typename AnyType>
void Swap(AnyType &a, AnyType &b)
{
AnyType temp;
temp = a;
a = b;
b = temp;
}
- 其中 template 和 typename 关键字是必须的,许多程序员会使用简单的 T 来代替 AnyType
- 编译器会检查参数的类型生成相应的函数,但函数模板不能缩短可执行程序,最终仍然会定义两个独立的函数
- 模板可以被重载
显式具体化
假如定义了以下结构:
struct job
{
char name[40];
double salary;
int floor;
};
假如只想交换 salary 和 floor 成员,上边的模板将无法使用,此时可以提供一个具体化函数定义,称为显式具体化。当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板。
下面是用于交换 job 结构的非模板函数,函数模板和具体化的原型:
void Swap(job &,job &);
template<typename T>
void Swap(T &,T &);
template<> void Swap<job>(job &,job &);
- 对于给定的函数名,可以有非模板函数,函数模板和显式具体化和它们的重载版本
- 显式具体化的原型和定义以 template<>打头,通过名称来指出类型
- 具体化优先于常规模板,非模板函数优先于具体化和常规模板
实例化和具体化
编译器使用模板为特定类型生成函数定义时,得到的是函数实例,编译器之所以知道实例化,是因为调用时提供了参数,称为隐式实例化。C++还允许显式实例化,其语法是:
template void Swap<int>(int,int);
该声明的意思是使用 Swap 模板生成 int 类型的函数定义。与显式实例化不同的是,显式具体化使用下面两个等价的声明:
template<> void Swap<int>(int &,int &);
template<> void Swap(int &,int &);
意味着不要使用模板来生成函数定义,而使用专门为int类型显式定义的函数定义。
类模板
定义类模板
C++利用类模板来生成通用的类声明,模板不能单独编译,必须与特定的模板实例化请求一起使用。以下是一个Stack为基础的模板:
template<typename T>
class struct
{
private:
enum{MAX = 10};
T items[Max];
int top;
public:
Stack();
bool isempty();
bool isfull();
bool push(const T & item);
bool pop(T & item);
};
template<typename T>
Stack<T>::Stack()
{
top = 0;
}
template<typename T>
bool Stack<T>::isempty()
{
return top == 0;
}
template<typename T>
bool Stack<T>::isfull()
{
return top == MAX;
}
template<typename T>
bool Stack<T>::push(const T & item)
{
if(top < MAX)
{
items[top++] = item;
return true;
}
else
return false;
}
template<typename T>
bool Stack<T>::pop(T & item)
{
if(top > 0)
{
item = items[--top];
return true;
}
else
return false;
}
使用模板类
仅在程序包含模板不能生成模板类,而必须请求实例化,必须显式提供所需的类型,这与函数模板不同,例如下面的代码创建两个栈,一个用于存储int,一个用于存储string:
Stack<int> i;
Stack<string> s;
模板具体化
模板可以隐式实例化,显式实例化,显式具体化,部分具体化