迭代器所指之物的型别便是其一。最常用的相应型别有5种,有的时候可以利用template参数推导机制来取得,而并非所有,所以需要更全面的解法。
Traits编程技法
迭代器所指对象的型别,就是迭代器的value type。参数推导机制虽然可用于value type;却非全面可用,如果value type必须要求用于函数的返回值,就不成立。Template参数推导机制推而导之的只是参数,无法推导函数的返回值型别。
声明内嵌型别可以解决返回值型别的问题。
template <class T>
struct MyIter{
typedef T value_type;
T* ptr;
MyIter(T *p=0):ptr(p){}
T& operator*()const{return *ptr;}
//....
};
template<class I>
typename I::value_type func(I ite)
{return *ite;}
//...
MyIter<int>ite(new int(8));
cout<<func(ite);
func()的返回型别必须加上typename,T是template的一个参数,在被编译器据西安华之前,编译器对T一无所知,编译器并不知道MyIter<T>::value_type代表的是什么,typename告诉编译器这是一个型别,才能通过编译。
新的问题出现:并不是所有的迭代器都是class type(只有它能够定义内嵌型别,如果无法定义内嵌型别,还是无法解决函数返回值型别的问题);原生指针就不是,所以引出新的解决方案。
TemplatePartial Specialization(偏特化)
Class template 如果有一个以上的template参数,,可以对其中的某个或者数个进行特化处理,可以再泛型设计中提供一个特化版本,将泛型化版本中某些template参数赋予明确的指定。
模板特化是通过"给模板中的所有模板参数一个具体的类"的方式来实现的.而模板偏特化则是通过"给模板中的部分模板参数以具体的类,而留下剩余的模板参数仍然使用原来的泛化定义"的方式来实现的.
template<class Window> //仍然使用原来的泛化定义;
class Widget<Window, MyController> //MyController是具体的类,是特化定义;
{
... 偏特化实现代码 ...
};
模板的偏特化能力很强大.当你实例化一个模板时,编译器会把目前存在的偏特化模板和全特化模板做比较,并找出其中最合适、最匹配的实现.
这样,灵活性就很大.
模板的偏特化机制不能用在函数身上,不论成员函数还是非成员函数.
我们便可以很快找到原生指针的偏特化版本:
template<typename T>
classC<T*>{….}
进入关键部分:
class template专门用来萃取迭代器的特性,而value type正是迭代器的特性之一。
<pre name="code" class="cpp">template<class I>
struct iterator_traits{
typedef typename I::value_type value_type ;}
这里所谓的traits就是如果I有自己定义的value type,那么通过这个traits作用,萃取出来的value_type就是I::value_type,换句话说,如果I有自己定义的value type,先前的func函数可以写成这样:
template<class I>
typenameiterator_traits<I>::value_type func(I ite){return *ite;}
中间多了一层间接性,traits可以拥有自己的偏特化版本。令iterator_traits拥有一个偏特化版本:
template<class T>
struct iterator_traits<*T>{
typedef T value_type ;}
原生指针int*虽然不是一种class type,也可以通过traits特性取其value type。这就解决了之前的问题。
但是,针对指向常数对象的指针,下面这个式子得到的结果:
iterator_traits<constint *>::value_type;
获得的是const int而非int,不是期望的(本来希望利用这种机制,声明一个暂时的变量,使其型别与迭代器的的value type相同,而声明一个无法赋值的暂时变量,没多大用处),所以应该设计一个特化版本:
template<class T>
Struct iterator_traits<T *>{
typedef T value_type;}//萃取出来的应该是T而非const T
特性萃取机traits能够有效运作,每一个迭代器都必须遵循约定,自行以内嵌型别定义的方式定义出相应的型别,这个是stl的一个约定。
最常用的迭代器相应型别:
template<class I>
struct iterator_traits{
typedef typename I::iterator_category iterator_category;
typedef typename I::value_type value_type;
typedef typename I::difference_type difference_type;
typedef typename I::pointer pointer;
typedef typename I::reference reference;}
iterators_traits必须对传入型别为pointer以及pointer—to-const设计特化版本。
differencetype表示两个迭代器之间的距离。如果一个泛型算法提供技术功能,例如count(),其传回值就必须使用迭代器的difference type:
template<class I,class T>
typename iterator_traits<I>::difference_type//这行是函数的返回值
count(I first,I last,,const T& value)
{
typename iterator_traits<I>::difference_type n=0;
for(;first!=last,++first)
if(*first!=value)
++n;
return n;}
类似于value type,difference type也设计了两个版本的偏特化版本,pointer和pointer-to-const版本。
referencetype pointer type