traits编程技法
iterator模式定义如下:提供一种方法,是指能够依次序寻访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达。
迭代器是一种智能指针
迭代器最重要的编程工作就是对opertor*和operator->进行重载工作。在算法中运用迭代器时,很可能会用到其相应型别。利用function template的参数推导机制,声明一个变量,以“迭代器所指对象的型别”为型别。
迭代器相应型别不只是“迭代器所指对象的型别”一种而已。最常用的相应型别有五种,然而并非任何情况下任何一种都可利用上述template参数推导机制来取得。
Traits编程技法——STL源代码门钥
函数的“template参数推导机制”推而导之的只是参数,无法推倒函数的返回值。声明内嵌型别可以推倒函数的返回值。例如:
template < class T>
struct MyIter{
typedef T value_type;//内嵌型别声明
T* ptr;
MyIter(T *p = 0):ptr(p){}
};
template < class I>
typename I::value_type func(I ite){//这一行是func的回返值型别
return *ite;
}
MyIter< int> ite(new int(8));
cout << func(site);
注意:func()的回返型别必须加上关键词typename,因为T是一个template参数,在它被编译器具现化之前,编译器并不知道MyIter::vaue_type代表的是一个型别或是一个member function或是一个data member,关键词typename的用意在于告诉编译器这是一个型别。
然而,并不是所有迭代都是class type,如果不是class type就无法为它定义内嵌型别,比如原声指针就不是class type,需要做特殊处理,使用template partial specialization可以做到。
Partial Specailization(偏特化)的意义
partial specialization的意义:“所谓partial specialization的意思是提供另一份template定义,而其本身扔为templatized”。
template< typename T>
class C{…};//这个泛化版本允许(接受)T为任何型别
类C的偏特化版本:
template< typename T>
class C< T* > {…};//这个特化版本仅适用于“T为原声指针”的情况
“萃取”迭代器的特性,而value type正是迭代器的特性之一:
template< class I>
struct iterator_traits{
typedef typename I::value_type value_type;
};
traits的意义是:如果I定义有自己的value type,那么通过这个traits的作用,萃取出来的value type就是I::value_type。这带来的好处是traits可以拥有特化版本。
最常用到的迭代器相应型别有五种:value_type, difference_type, pointer, reference, iterator category.
迭代器相应型别之一:value type
value type是指迭代器所指对象的型别,任何一个打算与STL算法搭配的class,都应该定义自己的value type内嵌型别
迭代器相应型别之二:difference type
difference type用来表示两个迭代器之间的距离,因此它也可以用来表示一个容器的最大容量,因为对于连续空间的容器而言,头尾之间的距离就是其最大容量。
例如STL的count(),其传回值就必须使用迭代器的difference type:
template < class I, class T>
typename iterator_traits< I >::difference_type
count(I first, T last, const T& value){
typename iterator_traits< I >::difference_type n = 0;
for(; first != last; ++first){
if(*first == value)
++n;
}
return n;
}
迭代器相应型别之三:reference type
从“迭代器所指之物的内容是否允许改变”可以将迭代器分为两种:
1.constant iterators:不允许改变“所指对象之内容”
2.mutable iterators:允许改变“所指对象之内容”
当我们对一个mutable iterators 进行提领操作时,获得的应该是一个左值,因为右值不允许赋值操作,左值允许。
在C++中, 函数如果要传回左值,都是以by reference的方式进行。
迭代器相应型别之四:pointer type
pointers和references在C++中有非常密切的关联。如果“传回一个左值,令它代表p所指之物”是可能的,那么“传回一个左值,令它代表p所指之物的地址”也一定是可以的。也就是说,我们能够传回一个pointer,指向迭代器所指之物。
迭代器相应型别之五:iterator_category
根据移动特性与施行操作,迭代器被分为五类:
input Iterator:这种迭代器所指的对象不允许外界改变,只读
Output Iterator:只写
Forward Iterator:允许“写入型”算法在此种迭代器所形成的区间上进行读 写操作
Bidirectional Iterator:可双向移动,某些算法需要逆向走访某个迭代器区间,可以使用Bidirectional Iterators.
Random Access Iterator:前四种迭代器都只供应一部分指针算数能力(前三种支持operator++, 第四种再加上operator–,第五种涵盖所有指针算数能力,包括p+n, p-n, p[n],p1-p2, p1