定义模板
函数模板
- 下面的两个函数,除了参数类型,其他完全相同
- 如果我们需要不同类型参数的相同函数
- 我们可以定义一个通用的函数模板,而不是为每个类型都定义一个新的函数
template <typename T>
int compare(const T &v1, const T &v2)
{
if(v1 < v2) retunrn -1;
if(v1 < v2) retunrn -1;
return 0;
}
//模板定义,以关键字template开始
//后跟一个模板参数列表
//这是一个以逗号分隔的一个或多个模板参数的列表,用<>包围起来
//eg:template <typename T, template U>
//注意,U前面的关键字是必须要有的
- 实例化函数模板
- 当我们调用一个函数模板时,编译器用函数的实参来推断模板实参
- cout<< compare(1, 0)<<endl; //T为int
- vector< int > vec1{1,2,3}, vec2{4,5,6};
- cout<< compare(vec1, vec2)<<endl; //T为vector< int >
template <typename T>
T foo( T *p)
{
T temp = *p;
...
return temp;
}
//意思就是,模板的类型参数的类型,也可以作为返回类型
-
非类型模板参数
- inline和constexpr的函数模板
- 函数模板可以声明为inline或constexpr的
- 将说明符放在模板参数列表之后,返回类型之前
template <typename T> inline T min(const T&, const t&); //正确
inline template <typename T> T min(const T&, const t&); //错误,说明符位置不对
- 模板的编译
- 当编译器遇到一个模板定义时,它不生成代码,只有当我们实例化出模板的一个特定版本时,编译器才会生成代码
-
模板特点: 模板的头文件通常既包括声明也包括定义!
- 大多数错误,在实例化期间报告
类模板
- 类模板是用来生成类的蓝图的
- 与函数模板不同的是,编译器不能为类模板推断参数类型
- 定义类模板
- 与函数模板类似,类模板以关键字template开始,后跟模板参数列表
- plus P568-570
//原先的类:
typedef unsigned long Item;
class Stack
{
private:
enum{MAX = 10};
Item items[MAX];
int top;
public:
Stack(); //默认构造函数
~Stock();
bool isfull() const;
bool push(Item &item);
}
//模板类
//就是将unsigned long 换为T
template <typename T>
class Stack
{
private:
enum{MAX = 10};
T items[MAX];
int top;
public:
Stack(); //默认构造函数
~Stock();
bool isfull() const;
bool push(T &item);
}
//函数:
//此处特别强调,要在函数前面加上:template <typename T>
template <typename T>
Stack<T>::Stack()
{
top=0;
}
template <typename T>
bool Stack<T>::isfull()
{
return top == MAX;
}
等等...
- 类模板与友元
- 模板类也可以有友元,分为三类:
- Plus P588
- 1.非模板的友元函数
//在模板类中,将一个常规函数声明为友元:
//它会成为,模板所有实例化后的类,的友元
template <typename T>
class HasFriend
{
public:
friend void counts();
...
}
//也可以这样:
template <typename T>
class HasFriend
{
public:
friend void counts(HasFriend <T> & );
...
}
- 2.约束模板友元
- 就是在类外声明
- 区别就是:每一个类的具体化,都对应着其各自的友元函数
//首先在类定义前面声明每个模板函数
template <typename T> void counts() ;
template <typename TT>
class HasFriendT //c是一个普通的类
{
...
friend void counts <TT> ();
...
}
- 3.非约束模板友元
- 在类内声明
- 其友元模板类型参数与模板类型参数是不同的
- 区别就是:所有具体化的类,都对应着一个友元函数
template <typename T>
class ManyFriend //c是一个普通的类
{
...
template <typename C, typename D> friend void show (C &, D 7);
...
}
- 模板参数
- 模板参数名的可用范围,是在其声明之后,至模板声明/定义结束之前
- 模板参数会隐藏外层作用域中声明的相同名字
- 但是,在模板内不能重用模板参数名
typedef double A;
template < typename A, typename B > void f(A a, B b)
{
A tmp = a; ///tmp的类型为模板参数A 的类型,而不是double
double B; //错误:重声明模板参数B
}