您的位置:首页 > 编程语言

Traits编程技法之iterator_traits

2016-12-06 18:52 197 查看
在设计容器时,避免不了的就是设计与之契合的迭代器。迭代器,行为类似指针,担任访问元素、提领元素的重任。为什么说是重任呢?因为访问、提领虽是简单易实现的操作,但也是使用频率最高的两个操作。使用频率高,即意味着任何对性能有着极大的影响,所以我们要对迭代器的类别进行细致的划分,力求将每一种迭代器的性能都发挥到极限。(例如vector的迭代器为原生指针,原生指针可以实现随机存取(Random
Access Iterator)。如果我们像是用笨拙的(相对来说)双向迭代器(Bidrectional Iterator)的一样,用++、--在相邻元素间移动,就太委屈他所拥有的能力了。)

我们首先对迭代器根据移动特性与操作方式(读、写),将其分为五类:

Input Iterator(输入迭代器):这种迭代器所指的对象,不允许外界改变。只能对其进行读操作。

Output Iterator(输出迭代器):这种迭代器所指的对象,只能对其进行写操作。

Forward Iterator( 可读可写迭代器):这种迭代器所指的对象,可以读取,也可以写入。

Bidrectional Iterator(双向迭代器):这种迭代器支持双向遍历,即支持++(递增),--(递减)操作,同时支持以上三种迭代器的操作。

Random Access Iterator(随机迭代器):这种迭代器支持跳跃式的对象处理能力,体现于支持[](根据索引值锁定目标),同时也支持以上所有迭代器的操作。

以上迭代器的能力具有层层扩展的关系,如何实现这种包含关系呢?最简单的方法就是继承:struct stl_input_iterator_tag{};//输入迭代器
struct stl_output_iterator_tag{};//输出迭代器
struct stl_forward_iterator_tag :public stl_input_iterator_tag{};//可读写迭代器
struct stl_bidirectional_iterator_tag :public stl_forward_iterator_tag{};//双向迭代器
struct stl_random_access_iterator_tag :public stl_bidirectional_iterator_tag{};//随机迭代器
如同type_traits(型别萃取),我们设立这几个类的目的是过后为其设置类型别名,以帮助我们区分迭代器。(这几个类别皆为全局变量)

那我们如何在迭代器上烙上迭代器类别的印记呢?

一种方法就是使用类型别名:

template<typename T>
class vector_Iterator
{
public:
typedef stl_random_access_iterator_tag iterator_category;

...

protected:
T* itor;
};
但对于每一个迭代器的实现都如此实现会涌现大量重复代码。为了避免重复,我们单独设置一个类别,专门定义迭代器相关的各种型别,再使迭代器类继承于它:

//型别集装箱,迭代器皆继承此类
template<typename Category,typename T,typename Distance=ptrdiff_t,
typename Pointer=T* ,typename Reference=T&>
struct iterator
{
typedef Category iterator_category;//迭代器类型
typedef T value_type;//迭代器所指对象类型
typedef Distance difference_type;//迭代器之间距离类型
typedef Pointer pointer;//迭代器所指对象的指针型别
typedef Reference reference;//迭代器所指对象的引用型别
};

注意,在这个类中定义的别名只是作为初始化作用,在迭代器的实现中,我们应为它们设立专属的别名(至少iterator_category应该重新定义为五种迭代器类型中的一种)。

我们再设立一个迭代器萃取装置:

//型别萃取器,类型型别由迭代器自主更改
template<typename Iterator>//模板参数应设为迭代器
struct stl_iterator_traits
{
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::Distance difference_type;
typedef typename Iterator::Pointer pointer;
typedef typename Iterator::Reference reference;
};

让此萃取装置作为外部包装,这样我们就可以隐藏迭代器的内部实现:

//copy算法的内层实现
template<typename InputIterator,typename OutputIterator>
struct _copy_dispatch
{
OutputIterator operator()(InputIterator first,InputIterator last,OutputIterator result)
{
typedef typename stl_iterator_traits<InputIterator>::iterator_category iterator_category;
return _copy(first,last,result,iterator_category());
}
};

因为原生指针的特殊性和代表性,我们可以为其实现特例化:
//特例化原生指针类型
template<typename T>
struct stl_iterator_traits<T*>
{
typedef stl_random_access_iterator_tag iterator_category;
typedef T value_type;
typedef T* pointer;
typedef ptrdiff_t diference_type;
typedef T& reference;
};

template<typename T>
struct stl_iterator_traits <const T*>
{
typedef stl_random_access_iterator_tag iterator_category;
typedef T value_type;
typedef const T* pointer;
typedef ptrdiff_t diference_type;
typedef const T& reference;
};


有了itertator_traits技术后,我们可以让拥有更高能力的迭代器完全发挥其性能优势。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息