迭代器的设计原则
在上一节4、list深度探索_努力的小带土的博客-优快云博客讲解list的时候,观察仔细的小伙伴一定注意到了,下面代码中五个typedef是迭代器中必不可少的组成部分。
template<class T, class Ref, class Ptr>
struct __list_iterator{
//所有的迭代器都要有这5个typedef
typedef bidirectional_iterator_tag iterator_category;//(1)
typedef T value_type;//(2)
typedef Ptr pointer;//(3)
typedef Ref reference;//(4)
typedef ptrdiff_t difference_type;//(5)
.......
}
那么它们到底起到什么作用呢?作用即是回答程序算法的疑惑。在算法程序中,往往都少不了对所调用容器进行属性详解,那么程序是如何知道你所调用容器是什么属性呢?就是通过上述迭代器中的五个typedef,那么算法是怎么使用它们的呢?看下述代码你便知晓。
template<calss I,class I>
inline void algorithm(I first,I last)
{
....
I::iterator_category;
I::value_type;//(2)
I::pointer;//(3)
I::reference;//(4)
I::difference_type;//(5)
}
上述代码,通过直接调用迭代器中的type来获取容器中的相关信息。
Iterator traits的作用与设计
首先我们来看一段程序图:
当我们调用算法rotate函数时,涉及到三个迭代器属性,在图片中已经标出。
那么算法提问和迭代器的回答既然能够直接查看引用,为什么要使用iterator::traits呢?原因是,若iterator不是class则没法在内部typedef。例如它是native pointer,这个时候便需要设计iterator::traits。这个traits必须有能力分辨所获得iterator是(1) iterator class T还是(2)native pointer to T。
通过下例代码,来告诉大家iterator::traits是如何提取信息的:
/*算法***/
template <typename I>
inline void algorithm(...)
{
typename iterator_traits<RandomAcessIterator>::value_type v1;
......
}
/*iterator::traits的偏具体化**/
/*1、如果I是class Iterator则进入此***/
template<typename I>
struct iterator_traits
{
typedef typename I::value_type value_type;
}
/*2、指针偏具体化**/
template<typename T>
struct iterator_traits<T*>
{
typedef T value_type;
}
/*3、第三个const 指针偏具体化**/
template<typename T>
struct iterator_traits<const T*>
{
typedef T value_type; // 注意此处是T而不是const T
}
通过类型T来进入1,2,3三种偏特化函数中。至于第三个偏特化函数,导入const T* 为什么最终不是typedef const T value_type 而是typedef T value_type,原因在于value_type的主要目的是用于申明变量,而申明一个没有办法被赋值的变量是没有意义的所以value_type不应该加上const T 。
其他四个问题(四个属性)的完整回答如下图所示: