模版不是类或函数,它们是c++编译器指令,它只是一个用于生成类或函数的方案,说明如何生成类或函数。 具体生成时,称为实例化(instantiation)或具体化(specialization)。因此,模版不能单独编译,必须与特定的实例化请求一起使用。最简单的办法就是将所有模版信息放入一个头文件里,使用时include这个头文件。如果编译器支持export关键词,则可以将“类模版” 的声明与定义分开存放在.h和.cpp中。
1. 函数模版的重载(利用可以重载的特征标)
template
<
class
Any
>
void
Swap(Any
&
a, Any
&
b);
//
override
template
<
class
Any
>
void
Swap(Any
*
a, Any
*
b,
int
n); template
<
class
Any
>
void
Swap(Any
&
a, Any
&
b)
...
{ Any temp; temp = a; a = b; b = temp; }
template
<
class
Any
>
void
Swap(Any
*
a, Any
*
b,
int
n)
...
{ Any temp; for ( int i = 0 ; i < n; i ++ ) ... { temp = a[i]; a[i] = b[i]; b[i] = temp; } }
main( )
{
int i, j;
double k[10], m[10];
Swap(i, j); //显示实例化为Swap<int>(int&, int&);
Swap(k, m, 10); //显示实例化为Swap<double>(double*, double*, int);
}
2. 函数模版的显式实例化,即可以命令编译器直接创建 template<class Any> 的实例,把 class Any 实例化。
//
explicit instantiation
template
void
Swap
<
int
>
(
int
&
,
int
&);
template
void
Swap
<
Cjob
>
(Cjob
&
, Cjob
&
);
3. 函数模版的显式具体化,它不使用模版来生成函数定义,而应使用独立的、专门的函数定义。显式具体化要有自己的函数定义,而显式实例化则不需要,这是两者本质的区别。两者的相同之处是:都生成了一个具体的函数,而不再是模板。
4. 函数模版的部分具体化,部分具体化与显式具体化的区别在于:前者还是一个函数模板,而后者则已经是一个函数。前者的函数定义中,必然还有typename类型待定,这个类型将在函数模板被调用的时候得到“隐式” 的具体化。
template
<
class
T1,
class
T2,
class
T3
>
void
Swap(T1
&
a, T2
&
b, T3
&
c);
//
explicit specialization
template
<
class
T1,
class
T2
>
void
Swap
<
T1, T2,
int
>
(T1
&
a, T2
&
b,
int
&
c);
//
部分具体化,可以引入各种限制
template
<
class
T1,
class
T2
>
void
Swap
<
T1,T2, T2
>
(T1
&
a, T2
&
b, T2
&
c); tempate
<
class
T1
>
void
Swap
<
T1, T1
*
, T1
*>
(T1
&
a, T1
*
&
b, T1
*
&
c); template
<
class
T1,
class
T2,
class
T3
>
void
Swap(T1
&
a, T2
&
b, T3
&
c)
...
{ .............. }
template
<
class
T1,
class
T2
>
void
Swap
<
T1, T2,
int
>
(T1
&
a, T2
&
b,
int
&
c)
...
{ .............. }
template < class T1, class T2 > void Swap < T1,T2, T2 > (T1 & a, T2 & b, T2 & c); ... { ............. }
template
<
class
T1
>
void
Swap
<
T1, T1
*
, T1
*>
(T1
&
a, T1
*
&
b, T1
*
&
c)
...
{ .............. }
5. 类模版之内与之外:在之内声明时可以忽略类型,之外必须Stack<Type>带上类型。
6. 类模版的默认类型参数,不能为函数模版提供默认的类型参数。
7a. 类模板的显式实例化
template
<
typename T
>
class
SortedArray
...
{ public : T val }
; template
class
SortedArray
<
int
>
; main ( )
...
{ SortedArray < int > sa; // 模板类与模板函数的区别在于:前者被调用时,总是要带有<parameter-type>,而后者则不带。因为后者可以从形式参数来实例化或具体化模板;而前者则只能靠这个后缀,由编译器决定生成哪种类型。(即使已经显式实例化了,也要带上后缀。) }
7b. 类模板的显式具体化
7c. 类模版的部分具体化
template
<
class
T1,
class
T2,
class
T3
>
class
SortedArray
...
{ public : SortedArray() ... { printf( " 1 " ); } T1 val1; T2 val2; T3 val3; }
; template
<
class
T1,
class
T2
>
class
SortedArray
<
T1, T2, T2
>
...
{ public : SortedArray() ... { printf( " 2 " ); } T1 val1; T2 val2; }
; template
<
class
T1
>
class
SortedArray
<
T1, T1, T1
>
...
{ public : SortedArray() ... { printf( " 3 " ); } T1 val; }
; template
<>
class
SortedArray
<
int
,
int
,
int
>
...
{ public : SortedArray() ... { printf( " 4 " ); } }
;
int
main(
int
argc,
char
*
argv[])
...
{ SortedArray < int , int , int > sa1; SortedArray < int , int > sa2; SortedArray < int > sa3; // SortedArray sa4; printf(" Hello World! " ); return 0 ; }
8. 模版作为模版类的成员
template
<
typename T
>
class
beta
...
{ private : template < typename V > class hold; hold < T > q; hold < int > n; public : template < typename U > U blab(U u, T t); }
;
//
member define
template
<
typename T
>
template
<
typename V
>
class
beta
<
T
>
::hold
...
{ private : V val; public : V Value() const ... { return val;} }
; template
<
typename T
>
template
<
typename U
>
U beta
<
T
>
::blab(U u, T t)
...
{ ........ }
;
9. 模版作为模版的参数,vc++不支持这种使用,g++支持。
template
<
typename V
>
class
Stack
...
{ .... }
; template
<
template
<
typename T
>
class
Thing
>
class
Crab
...
{ .... }
; main()
...
{ Crab < Stack > vStack; }
10. 模版类的非模版友元函数
template
<
typename T
>
class
HasFriend
...
{ public : HasFriend( const T & i) : item(i) ... { ct ++ ; } ~ HasFriend() ... { ct -- ; } friend void counts(); friend void report(HasFriend < T > & ); private : T item; static int ct; }
;
void
counts()
...
{ // 每个类有独立的static变量,模版没有static变量,因为模版只是提供给编译器的方案,本身并不是类。只有模版实例化或具体化之后,才可以访问其static变量。 cout << " HasFriend<int>: " << HasFriend < int > ::ct; cout << " HasFriend<double>: " << HasFriend < double > ::ct; }
//
必须为每个类提供相应的友元。
void
report(HasFriend
<
int
>
&
hf)
...
{ cout << hf.itme; }
void
report(HasFriend
<
double
>
&
hf)
...
{ cout << hf.item; }
main()
...
{ HasFriend < int > hf1; counts(); HasFriend < double > hf2; counts(); report(hf2); }
10. 模版类的约束模版友元。
//
首先在类定义前面声明-函数是模版函数
template
<
typename T
>
void
counts(); template
<
typename T
>
void
report(T
&
); template
<
typename TT
>
class
HasFriendT
...
{ public : HasFriendT( const TT & i) : item(i) ... { ct ++ ; } ~ HasFriendT() ... { ct -- ; } // 在类里再次声明为友元,这里也是某种程度上的实例化, // 但还没有彻底实例化,函数还是模版。 friend void counts < TT > (); friend void reports < HasFriendT < TT > > (HasFriendT < TT >& ); // 这里也可以写做: // friend void reports<> (HasFriendT<TT>&); // 让编译器自己判断模版的参数类型! private : TT item; static int ct; }
; template
<
typename T
>
int
HasFriendT
<
T
>
::ct
=
0
; template
<
typename T
>
void
counts()
...
{ // 这里并不是要输出模版的大小、模版的static成员变量。因为程序运行时,并不存在模版的实体, // 都是实例化后的确确实实存在的类。因此,这里指的实例化的类。 cout << " template size: " << sizeof (HasFriendT < T > ) << " ; " ; cout << " template counts(): " << HasFriendT < T > ::ct << endl; }
template
<
typename T
>
void
report(T
&
hf)
...
{ cout << hf.item << endl; }
int
main()
...
{ counts < int > (); // 隐式实例化counts,由模版函数变为具体的函数 HasFriendT< int > hfi1( 10 ); // 隐式实例化类,并定义该实例化类的一个对象 HasFriendT < int > hfi2( 20 ); HasFriendT < double > hfdb( 10.5 ); report(hfi1); // 通过调用,隐式实例化函数 report(hfi2); report(hfdb); return 1 ; }
11. 模版类的非约束模版友元。
template
<
typename T
>
class
ManyFriend
...
{ public : ManyFriend( const T & i) : item(i) ... {} template < typename C, typename D > friend void show2(C & , D & ); private : T item; }
; template
<
typename C, typename D
>
void
show2(C
&
c, D
&
d)
...
{ cout << c.item << " , " << d.item << endl; }
int
main()
...
{ ManyFriend < int > hfi1( 10 ); ManyFriend < int > hfi2( 20 ); ManyFriend < double > hfdb( 10.5 ); cout << " hfi1, hfi2: " ; show2(hfi1, hfi2); cout << " hfdb, hfi2: " ; show2(hfdb, hfi2); return 0 ; }