文章目录
模板(Template)指C++程序设计设计语言中采用类型作为参数的程序设计,支持通用程序设计。C++ 的标准库提供许多有用的函数大多结合了模板的观念,如STL以及IO Stream。模板是C++支持参数化多态
的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
模板是一种对类型进行参数化的工具,通常有两种形式:函数模板
和 类模板
;
- 函数模板:针对仅参数类型不同的函数;
- 类模板:针对仅数据成员和成员函数类型不同的类。
使用模板的目的就是能够让程序员编写与类型无关的代码。
C++只有模板显式实例化(explicit instantiation),隐式实例化(implicit instantiation),特化(specialization,也译作具体化,偏特化)。
类模板定义
- 定义:
template<typename 形参名,typename 形参名,…>
class 类名{ ... };
- 示例如下:
template <class T>
class Arrary
{
private:
T* ar;
int l;
...
};//template class declaration.
- 类外定义成员函数:
函数返回类型 类名<模板形参名>::函数名(参数列表){函数体}
注意:
- 类模板不能重载,可以全特化、偏特化。
- 对主版本模板类、全特化类、偏特化类的调用优先级从高到低进行排序是:
全特化类 > 偏特化类 > 主版本模板类
- 由于编译器只能通过include <看到> 头文件而找不到模板实现代码。为避免产生链接问题,模板类的声明和定义必须放在一起(头文件中)
函数模板定义
- 定义:
template <class 形参名,class 形参名,......>
返回类型 函数名(参数列表)
{
函数体
}
其中template和class是关键字,class
可以用typename
关键字代替,在这里typename 和class没区别,<>括号中的参数叫模板形参,模板形参和函数形参很相像,模板形参不能为空。
- 示例如下:
template<class T>
void swap(T &a, T &b )
{
T temp;
temp = a;
a = b;
b = temp;
};
注意:
- 函数模板是可以被重载的(类模板不能被重载),也就是说允许存在两个同名的函数模板,还可以对它们进行实例化,使它们具有相同的参数类型。
- 函数模板只能全特化,不可以偏特化。
函数模板重载
// 主模板函数
template<typename T, class N> void func(T num1, N num2)
{
//cout << "num1:" << num1 << ", num2:" << num2 <<endl;
}
// 重载模板函数
template<class N> void func(int num1, N num2)
{
cout << "num1:" << num1 << ", num2:" << num2 <<endl;
}
// 重载模板函数
template<class N> void func(N num1)
{
cout << "num1:" << num1 <<endl;
}
隐式实例化 implicit instantiation
模板只有在运行时才会生成相应的实例,会影响执行效率。
编译器进行类型推导,在编译期间生成相应的实例
swap<int>(a,b);
其中<int>
是可省的
Array<int> arr;
其中<int>
是不可省的
显式实例化 explicit instantiation
显式实例化,需要在模板定义后显式声明,在编译期间生成相应的实例。 虽然会增加编译时间,但提高了执行效率。
注意显式实例化的写法:
template void swap<int>(int &a,int &b);
template class Array<int>; //explicit instantiation. 显式实例化
模板特化/具体化 specialization
对于函数模板,只有全特化,不能偏特化。偏特化功能可以通过模板函数的重载实现。
对于类模板,可以全特化、偏特化,但不能重载。(没有重载类的说法)
C++模板全特化之后已经失去了Template的特性。
一个模板被全特化/偏特化的条件:
- 必须有一个主模板类
- 模板类型被全部/部分明确化
函数模板的全特化
// 主模板
template<typename T, class N>
void func(T num1, N num2)
{
//cout << "num1:" << num1 << ", num2:" << num2 <<endl;
}
// 全特化模板
template<>
void func(int num1, double num2)
{
cout << "num1:" << num1 << ", num2:" << num2 <<endl;
}
类模板的全特化
注意全特化类的定义写法
// 主模板
template<typename T, class N>
class Test_Class
{
public:
static bool comp(T num1, N num2)
{
return (num1<num2)?true:false;
}
};
// 全特化模板
template<>
class Test_Class<int, double>
{
public:
static bool comp(int num1, double num2)
{
return (num1<num2)?true:false;
}
};
类模板的偏特化
注意偏特化类的定义写法
// 主模板
template<typename T, class N>
class Test_Class
{
public:
static bool comp(T num1, N num2)
{
return (num1<num2)?true:false;
}
};
// 偏特化模板
template<class N>
class Test_Class<int, N>
{
public:
static bool comp(int num1, double num2)
{
return (num1<num2)?true:false;
}
};
特化和重载的区别
不能将特化和重载混为一谈。全特化和偏特化都没有引入一个全新的模板或者模板实例。它们只是对原来的泛型(或者非特化)模板中已经隐式声明的实例提供另一种定义。