SGISTL源码阅读五 迭代器上(迭代器的五种相应型别associated types)
前言
之前在对STL的简介中说到过,迭代器的作用是将数据结构(容器)和算法粘合在一起,我们可以将它理解成smart pointer,它是一种行为类似指针的对象。
什么是相应型别?
最初看到这个翻译觉得这个概念特别高大上,但是我们不要把它想得太复杂。
相应型别其实就是其字面意思,它可以指迭代器所指对象的类型,但是它又不止于此,常用的迭代器相应型别有五种,分别是
- iterator_category
- value_type
- difference_type
- pointer
- reference
为什么要会存在相应型别?
我们知道迭代器的作用是将不同的数据结构和算法粘合在一起,如果仅仅只针对一种数据结构,那当然是很简单的了,原生指针都可以做到。迭代器使用相应型别,针对不同的类型使用不同的方式(通过模板偏特化实现),这样能大大提高地效率。
五种相应型别的详细介绍
iterator_category
根据移动特性与施行操作,迭代器被分为了五类,iterator_category
区分了这五类迭代器。
- Input Iterator
这种迭代器所指的对象不允许外界改变(Read Only) - Output Iterator
与上一个迭代器类似,这个迭代器所指的对象,Write Only - Forward Iterator
这种迭代器允许在其所形成的区间上进行读写操作,但是只能向前(operator++) - Bidirectional Iterator
同样可以进行读写操作,并且可以双向移动(operator++,operator–) - Random Access Iterator
第五种类型涵盖了之前所有指针的算术能力(相加,相减,通过下标访问等)
他们的从属关系为:
value_type
这就是迭代器所指对象的类型。(类型==型别,但是更通俗一些)
difference_type
difference_type
用来表示两个迭代器之间的距离,也可以用来表示一个容器的最大容量(因为对于连续空间的容器而言,头尾之间的距离就是其最大容量)。
pointer
这里的pointer
型别其实就是指针。
reference_type
其实也很好理解,用我们最初在学习函数的时候的一个经典样例来说,交换a、b的值,其实就是传值和传引用的区别,这里的reference_type
就是引用。按照是否能改变迭代器所指之物来分,迭代器可以分为两种:
1.constant iterators
,不允许改变所指对象内容;
例如带有const修饰符的,就不能被改变
2.mutable iterators
,允许改变所指对象内容。
深入源码
//从这里我们可以看到不同类型迭代器之间 的继承关系
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
template <class T, class Distance> struct input_iterator {
typedef input_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
struct output_iterator {
typedef output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
};
template <class T, class Distance> struct forward_iterator {
typedef forward_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T, class Distance> struct bidirectional_iterator {
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T, class Distance> struct random_access_iterator {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
在进行了一些分析之后再看源码其实很好懂了,根据迭代器的五种类型创建了5个相应的结构体,他们都是统一地,拥有五种相应型别。
参数推导机制
大家应该比较熟悉sizeof()
吧,我们可以调用它来获取变量的长度,但是至于变量的类型呢?C++并未支持typeof()
,但是可以使用 参数推导机制 ,一旦函数被调用,编译器会自动进行template参数推导。
总结
以上简要介绍了迭代器的五种相应型别和迭代器的类型
但是并非任何情况下任何一种相应型别都可以利用上述的template参数推导机制来取得的。
后面我们将介绍到traits
编程技法。