  | 任意类(模板或者是飞模板)可以拥有类模板或函数模板的成员,这种成员成为成员模板,成员模板不能为虚。成员模板的一个例子是标准容器的assign成员,接受两个迭代器的assign版本使用模板形参表示其迭代器形参的类型。另一个例子就是接受两个迭代器的容器构造函数。
 1 定义成员模板
 模板成员声明看起来像任意模板的声明一样。
  
 ?
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 template <class Type=""> class Queue{
 public:
 template <class It="">Queue(It beg,It end){
 copy_elems(beg,end);
 }
 template <class Iter=""> void assign(Iter,Iter);
 private:
 template <class Iter=""> void copy_elems(Iter,Iter);
 };
  
 template <class Type=""> template <class Iter="">
 void Queue<type>::assign(Iter beg,Iter end){
 //destroy();
 copy_elems(beg,end);
 }
  
 template <class Type=""> template <class Iter="">
 void Queue<type>::copy_elems(Iter beg,Iter end){
 while(beg != end){
 push(*beg);
 ++beg;
 }
 }</type></class></class></type></class></class></class></class></class></class>
 成员声明的开头是自己的模板形参表。构造函数和assign函数各有一个模板类型形参,这些函数使用这些类型形参作为其函数形参的类型,他们函数
  
 形参指明要复制元素范围的迭代器。
 
  
 2 在类外定义成员模板
 在类模板作用域外部定义成员模板的时候,那必须包含两个模板形参表:
  
 ?
 1
 2
 3
 4
 5
 template <class Type=""> template <class Iter="">
 void Queue<type>::assign(Iter beg,Iter end){
 //destroy();
 copy_elems(beg,end);
 }</type></class></class>
 
 当成员模板时类模板的成员时,它的定义必须包含类模板形参以及自己的模板形参。
 首先是类模板形参表,后面接着是自己模板形参表。
 assign函数定义的开头为:
 template template 
 第一个模板形参表template 为类模板的,第二个模板形参表template 是成员模板的。
 3 成员模板的实例化
 成员模板只有在程序使用时才实例化。类模板的成员模板的实例化要比类模板的普通成员函数的实例化要复杂一些。
 成员模板有两种模板形参:(1)由类定义的(2)由成员模板本身定义的
 类模板形参由调用函数的对象的类型确定,成员定义的模板形参的行为与普通函数模板一样。这些形参都通过常规模版实参推断确定。
  
 ?
 1
 2
 3
 4
 5
 short a[4] = {0,3,6,9};
 Queue<int> qi(a,a+4);
 vector<int> vi(a,a+4);
 qi.assign(vi.begin(),vi.end());
 </int></int>
 
 因为所构造的是Queue类型的对象,我怕们知道编译器将为Queue实例化基于迭代器构造函数。该构造函数本身模版形参的类型由编译器根据a和a+4的类型推断,而该类型为short指针。因此,qi的定义实例化:
 void Queue::Queue(short *,short *);
 对assign的调用将实例化qi的成员。qi具有Queue类型,因此,这个调用将实例化名为assign的Queue成员。该函数为函数模版,想起他任意的函数模版一样,编译器从传给调用者的实参推断assign的模版实参,推断得到的类型是vector::iterator,这个调用实例化:
 void Queue::assign(vector::iterator,vector::iterator); 
  |  |