一、模板的定义与使用
模板定义以
template
开头,后跟一对尖括号,尖括号内是模板形参列表,以逗号隔开,不能为空。形参的类型是
class
或
typename
,它们是等价的。
template
<
typename T1,
class
T2
>
…….
…….
一个典型的函数模板
template
<
typename T
>
int compare ( const T & v1, const T & v2)
... {
if (v1<v2) return -1;
if (v2<v1) return 1;
return 0;
}
int compare ( const T & v1, const T & v2)
... {
if (v1<v2) return -1;
if (v2<v1) return 1;
return 0;
}
compare(1,2);
compare<int>(1,2);
2
、类模板
一个典型的类模板
template
<
typename T
>
class stack
... {
public:
void push (const T&);
T pop();
bool empty();
private:
vector<T> m_vector;
}
class stack
... {
public:
void push (const T&);
T pop();
bool empty();
private:
vector<T> m_vector;
}
类外定义成员函数的格式:
template
<
typename T
>
ret_type stack < T > ::member - name
ret_type stack < T > ::member - name
3
、特别说明
Ø
模板声明和实现中的形参名称不必相同
Ø
模板形参的名字不可在模板内部重用
Ø
在模板内部指定类型时要使用
typename
关键字。
typename Param::size_type * p; //
区别指针和乘积
Ø
模板的形参可以是非类型的,但必须是常量表达式。
二、模板实例化
产生具体类型的模板实例的过程叫做实例化。前面已经说过,类模板的实例化必须指定类型,函数则可不指定,编译器会代劳推导出来的。另外需要注意的是
stack<int>
和
stack<string>
是完全不同的两种类型,他们之间没有任何的瓜葛,相互不具有特殊的访问权限。
1、
模板实参推断
Ø
多个模板类型形参的实参必须完全匹配
加入
sh
是
short
类型,则
compare(sh, 1024)
是错误的调用,因为第一个参数匹配
short
,而第二个匹配
int
,导致推断错误。
Ø
模板类型形参的受限转换
模板实参只会进行两种转换:一是
const
转换,即形参为
const
指针或引用的函数接受非
const
的指针和引用的调用;一是数组或函数到指针的转换。
三、模板特化
针对特殊类型作出特殊处理
1、
函数模板特化
template
<>
function < T > (…)
... {
…
}
function < T > (…)
... {
…
}
template
<>
classname < T >
... {
…
} ;
classname < T >
... {
…
} ;
template
<>
void stack < int > ::push( const int & val)
... {
…
}
void stack < int > ::push( const int & val)
... {
…
}
3、
偏特化
只特化模板形参的一部分而非全部。
4、
重载与函数模板
如果重载函数中既有普通函数又有函数模板,确定函数调用的步骤如下(非模板函数优先):
Ø
为这个函数名建立候选函数集合,包括:同名的任意普通函数,同名的类型匹配的函数模板实例化
Ø
确定那些普通函数是可行的,模板实例都是可行的(因为是编译器推导出来的)
Ø
如果需要转换来进行调用,根据转换的种类排列可行函数。如果只有一个函数可选,则调用它;如果调用具有二义性,从可行函数集合中去掉所有函数模板实例
Ø
重新排列去掉函数模板实例的可行函数。如果只有一个函数可选,则调用;否则具有二义性。