iterator模式定义如下:提供一种方法,使之能够依序寻访某个聚合物所含的各个元素,而又无需暴露该聚合物的内部表达形式
其中,c++里面各个容器的iterator扮演着将数据容器与算法结合起来的重要角色
将范型算法(find, count, find_if)用于某个容器中,最重要的是要给算法提供一个访问容器元素的工具,iterator
就扮演着这个重要的角色
我们在算法中可能会定义简单的中间变量或者设定算法的返回变量类型,这时候需要知道迭代器所指元素的类型是什么,但是由于没有typeof
这类判断类型的函数,我们无法直接获取,那该如何是好?
不要急,那首先先介绍一下iterator_tarit
iterator_trait
1 | template<class _Tp> |
看到这个奇奇怪怪的东西,是不是感觉没什么用,嗯,没关系,先记着
下面,将接着之前的话题,来看看如何提取出iterator
所指向的元素类型
value_type
例如
使用typedef
我们可以在迭代器中添加元素的类型
1 | template <class T> |
但是,这个版本并不支持原生指针,然而就迭代器的行为而言,就是面向容器的指针,而正常的STL算法也是支持原生指针的,就如同下面的find一样
指针和迭代器的作用无非就是为stl算法提供了一个运算范围以及对容器(无论是vector,list,亦或是array)的访问
1 | int main() { |
所以对于第一个版本,我们还要对指针类型进行模版偏特化
提取以及偏特化
前面也提到了,如果直接使用typename I::value_type
,算法就无法接收原生指针,因为原生指针根本就没有value_type
这个内嵌类型
因此,我们还需要加入一个中间层对其进行判断,看它是不是原生指针,注意,这就是traits
技法的妙处所在
如果我们只使用上面的做法,也就是内嵌value_type
,那么对于没有value_type
的指针,我们只能对其进行偏特化,这种偏特化是针对可调用函数get
的偏特化,假如get
有100行代码,那么就会造成极大的视觉污染
1 |
|
就如同上面这个形式,设想往get中填充100行代码,简直不忍直视,你再看看下面这个,简直优雅!
利用一个中间层iterator_traits
固定了get
的形式,使得重复的代码大量减少,唯一要做的就是稍稍特化一下iterator_tartis
使其支持pointer
和const pointer
:)
1 |
|
通过定义内嵌类型,我们获得了知晓iterator
所指元素类型的方法,通过traits
技法,我们将函数模板对于原生指针和自定义iterator
的定义都统一起来
这就是traits
技法的妙处所在
difference type
difference type
用于表示两个迭代器之间的距离的一个类型,也可以用来表示一个容器的最大的容量,因为对于连续空间的容器,头尾之间的距离就是最大容量
例如count()
就必须返回的类型就是迭代器的difference type
对于STL容器类型,以及原生指针,traits有如下两个不同版本
1 | template<class I> |
reference type
标示了引用类型
pointer
标示了指针类型
测试
以上说明了迭代器内部的几种重要类型
下面对其进行一个测试,以此产生一个更直观的印象
1 |
|
从上面可以看出,一个vector<int>::iterator
value_type
=int
difference_type
=ptrdiff_t
reference
=int&
pointer
=int*
总结
要牢记iterator
是为了访问容器内的元素而存在的,而它内置的类型就是范型算法与容器进行沟通的重要工具
而我们使用traits
技法主要是为了解决原生指针和自定义iterator
之间的不同所造成的代码冗余
type traits
type traits
的出现和STL对于性能的要求有着千丝万缕的联系
试想,对于vector
这种大块分配内存,然后大块析构的容器,如果容器里面是POD的话,那么只要等它的生命周期结束就行了,如果是非POD的话,那么就要判断是否拥有no-traits
的析构函数
如果是这样的话,又回到了之前value_type
的窘境,因此,我们只需要使用type_traits
,对POD进行偏特化,通过两个神奇的类型进行判断
1 | struct _true_type{};//无意义的析构函数 |
这样子就可以让负责析构的模块进行判断了
具体的type_traits
如下所示
1 | template<typename T> |
总结
通过对type_traits
进行特化,标注自己类中的构造,拷贝等行为是否是有意义的,可以大大提高适配算法的效率,这也是type traits
存在的意义