模版不是类或函数,它们是c++编译器指令,它只是一个用于生成类或函数的方案,说明如何生成类或函数。 具体生成时,称为实例化(instantiation)或具体化(specialization)。因此,模版不能单独编译,必须与特定的实例化请求一起使用。最简单的办法就是将所有模版信息放入一个头文件里,使用时include这个头文件。如果编译器支持export关键词,则可以将“类模版”的声明与定义分开存放在.h和.cpp中。
1. 函数模版的重载(利用可以重载的特征标)
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; }
}
2. 函数模版的显式实例化,即可以命令编译器直接创建 template<class Any> 的实例,把 class Any 实例化。
template void Swap < int > ( int & , int &);
template void Swap < Cjob > (Cjob & , Cjob & );
3. 函数模版的显式具体化,它不使用模版来生成函数定义,而应使用独立的、专门的函数定义。显式具体化要有自己的函数定义,而显式实例化则不需要,这是两者本质的区别。两者的相同之处是:都生成了一个具体的函数,而不再是模板。
template <> void Swap < Cjob > (Cjob & a, Cjob & b);
template <> void Swap(Cjob & a, Cjob & b);
template <> void Swap < Cjob > (Cjob & a, Cjob & b)
{
string tStr;
tStr = a.name;
a.name = b.name;
b.name = tStr;
}
template <> void Swap(Cjob & a, Cjob & b)
{
string tStr;
tStr = a.name;
a.name = b.name;
b.name = tStr;
}
4. 函数模版的部分具体化,部分具体化与显式具体化的区别在于:前者还是一个函数模板,而后者则已经是一个函数。前者的函数定义中,必然还有typename类型待定,这个类型将在函数模板被调用的时候得到“隐式”的具体化。
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 > void Swap < T1, T1 * , T1 *> (T1 & a, T1 * & b, T1 * & c)
{
..............
}
5. 类模版之内与之外:在之内声明时可以忽略类型,之外必须Stack<Type>带上类型。
class Stack
{
public:
Stack& operator= (const Stack& st);
}
template < class Type >
Stack < Type > & Stack < Type > :: operator = ( const Stack < Type >& st)
{
}
6. 类模版的默认类型参数,不能为函数模版提供默认的类型参数。
class Topo
{
........
} ;
7a. 类模板的显式实例化
class SortedArray
{
public:
T val
} ;
template class SortedArray < int > ;
main ( )
{
SortedArray<int> sa; //模板类与模板函数的区别在于:前者被调用时,总是要带有<parameter-type>,而后者则不带。因为后者可以从形式参数来实例化或具体化模板;而前者则只能靠这个后缀,由编译器决定生成哪种类型。(即使已经显式实例化了,也要带上后缀。)
}
7b. 类模板的显式具体化
class SortedArray
{
........
} ;
// 显式具体化,定义新的类功能。
template <> class SortedArray < specialized - type - name >
{
........
} ;
7c. 类模版的部分具体化
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. 模版作为模版类的成员
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++支持。
class Stack
{
....
} ;
template < template < typename T > class Thing >
class Crab
{
....
} ;
main()
{
Crab<Stack> vStack;
}
10. 模版类的非模版友元函数
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. 模版类的非约束模版友元。
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;
}