1. 函数模板
1.1 函数模板概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定
类型版本。
1.2 函数模板格式
template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名
(
参数列表
){}
注意:
typename
是
用来定义模板参数
关键字
,
也可以使用
class(
切记:不能使用
struct
代替
class)
例如:
template
<
typename
T
>
void
Swap
(
T
&
left
,
T
&
right
)
{
T temp
=
left
;
left
=
right
;
right
=
temp
;
}
1.3 函数模板的实例化
1.
隐式实例化:让编译器根据实参推演模板参数的实际类型
例如:
template
<
class
T
>
T
Add
(
const
T
&
left
,
const
T
&
right
)
{
return
left
+
right
;
}
int
main
()
{
int
a1
=
10
,
a2
=
20
;
double
d1
=
10.0
,
d2
=
20.0
;
Add
(
a1
,
a2
);
Add
(
d1
,
d2
);
/*
Add(a1, d1); 该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参的类型通过实参a1
将
T
推演为
int
,通过实参
d1
将
T
推演为
double
类型,但模板参数列表中只有一个
T
,编译器无法确定此处到底该将T
确定为
int
或者
double
类型而报错
注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
*/
//
此时有两种处理方式:
1.
用户自己来强制转化
2.
使用显式实例化
Add
(
a1
, (
int
)
d1
);
2.
显式实例化:在函数名后的
<>
中指定模板参数的实际类型
如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。
例如:
int
main
(
void
)
{
int
a
=
10
;
double
b
=
20.0
;
//
显式实例化
Add
<
int
>
(
a
,
b
);
return
0
;
}
1.4 模板参数的匹配原则
1.
一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函
数
例如:
//
专门处理
int
的加法函数
int
Add
(
int
left
,
int
right
)
{
return
left
+
right
;
}
//
通用加法函数
template
<
class
T
>
T
Add
(
T left
,
T right
)
{
return
left
+
right
;
}
void
Test
()
{
Add
(
1
,
2
);
//
与非模板函数匹配,编译器不需要特化
Add
<
int
>
(
1
,
2
);
//
调用编译器特化的
Add
版本
}
2.
对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模
板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板 .
例如
void
Test
()
{
Add
(
1
,
2
);
//
与非函数模板类型完全匹配,不需要函数模板实例化
Add
(
1
,
2.0
);
//
模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的
Add
函数
}
2. 类模板
2.1 类模板的定义格式
template
<
class
T1
,
class
T2
, ...,
class
Tn
>
class
类模板名
{
//
类内成员定义
};
举例:
//
动态顺序表
//
注意:
Vector
不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template
<
class
T
>
class
Vector
{
public
:
Vector
(
size_t
capacity
=
10
)
:
_pData
(
new
T
[
capacity
])
,
_size
(
0
)
,
_capacity
(
capacity
)
{}
//
使用析构函数演示:在类中声明,在类外定义。
~Vector
();
void
PushBack
(
const
T
&
data
)
;
void
PopBack
()
;
// ...
size_t
Size
() {
return
_size
;}
T
&
operator
[](
size_t
pos
)
{
assert
(
pos
<
_size
);
return
_pData
[
pos
];
}
private
:
T
*
_pData
;
size_t
_size
;
size_t
_capacity
;
};
//
注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template
<
class
T
>
Vector
<
T
>
::
~Vector
()
{
if
(
_pData
)
delete
[]
_pData
;
_size
=
_capacity
=
0
;
}
2.2 类模板的实例化
类模板实例化与函数模板实例化不同,
类模板实例化需要在类模板名字后跟
<>
,然后将实例化的类型放在
<>
中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
。
举例:
// Vector
类名,
Vector<int>
才是类型
Vector
<
int
>
s1
;