Iterator traits
迭代器类别详解
迭代器有5中类别,如下图:
这里的关系并不是继承,而是强化。比如一个算法可以接受 Random Access Iterator,那么它也能接受 Forward Iterator,反之不然。
一个迭起器,应当落在能支持的最强化的哪一个,如 int* 可以被归入多个,它将选择最强的 Random Access Iterator
以 advance() 为例子,它定义了3个版本,分别是 Input Iterator,Bidirectional Iterator 和 Random Access Iterator,分别支持 单向逐一前进(迭代器只能++,不能+n),双向逐一前进,双向跳跃前进
当调用advance()时,如果选择 Input Iterator,对于 Random Access Iterator 而言遍历复杂度从 O(1) 变成 O(n)
如果选择 Random Access Iterator,则无法接受 Input Iterator
一种简单的方法,在advance()内部对迭代器类型进行 if-else 判断,但这样在执行期间才能判断使用哪一个版本,缺乏效率
更好的方法是在编译期间就确定下来:给advance添加第3个参数,形成重载函数
定义多个 _advance函数,例如 _advance(RandomAccessIterator& i, Distance n, random_access_iterator_tag)
注意最后一个参数只声明类型,没有参数名称,因为它只是用来激活函数,在函数实现中不会使用
最后,还还要一个上层接口 advance 和调用者对接,它只需要两个参数
//这里需要特别注意的是,STL算法的一个命名规则:以能接收的最低阶的迭代类型来为参数命名,因此这里是class InputIterator
template <class InputIterator, class Distance>
inline void advance(InputIterator& i, Distance n){
return __advance(i, n, iterator_traits<InputIterator>::iterator_category());
}
因此,iterator需要定义一个类型,即 iterator_category
传递调用
distance()和advance()的设计如出一辙,它可以接收任何类型的迭代器。以它为例,当调用distance(),并使用 Output Iterator,Forward Iterator,Bidirectional Iterator时,由于继承关系的存在,统统都会传递调用 Input Iterator 那个版本的 __distance()函数
这是因为上层接口 distance() 中将以最低阶的 InputIterator 来接收所有类别参数,当调用 __distance发现这一参数和 iterator_traits中的 category不一样时,就会去调用父类的那一种实现
源码总览:stl_iterator_base_types
在 list 容器的源码中,可以看到 _List_iterator 中定义了如下内容:
template<typename _Tp>
struct _List_iterator {
......
typedef ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Tp* pointer;
typedef _Tp& reference;
......
}
difference_type,iterator_category,value_type,pointer,reference是迭代器必要的5个属性,这些属性是萃取器的要求
在文件 bits/stl_iterator_base_types.h中,定义了迭代器的萃取器如下:
- 主要是对5种迭代器类型和5种要萃取的特性的说明
- 函数实现在stl_iterator_base_func.h文件当中
- 运算符重载在stl_iterator.h文件当中
//表示只读迭代器
struct input_iterator_tag { };
//只写迭代器
struct output_iterator_tag { };
//允许“写入”型算法,如replace()
struct forward_iterator_tag : public input_iterator_tag { };
//可双向移动
struct bidirectional_iterator_tag : public forward_iterator_tag { };
//可随机访问,支持所有指针算术能力。前3种支持++,第4种再加上--
struct random_access_iterator_tag : public bidirectional_iterator_tag { };
/*
目的:iterator class不含任何成员,只是单纯的类别定义,如果每一个新设计的iterator都继承自它,就可以保证符合STL规范
想要适配地使用STL算法,那么迭代器一定要定义以下5种类型,后2个都有默认值,如需使用只需要给出 _Category 和 _Tp
list虽然没有继承,但也自行定义了这5个类型。自行开发的迭代器最好都继承自这个iterator classs
*/
template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t,
typename _Pointer = _Tp*, typename _Reference = _Tp&>
struct iterator {
//1. 迭代器的类型,上面5种中的一个
typedef _Category iterator_category;
//2. 迭代器所指对象的类型,例如list<int>l,那么value_type就是int的类型别名
typedef _Tp value_type;
//3. 两个迭代器之间的举例,常用来表示一个容器的最大容量。如STL的count()就会使用到difference_type
//ptrdiff_t是一种数据类型,用来保存两个指针减法操作的结果,常被定义为long int
//当需要使用任何迭代器的difference_type,可以这样写:typename iterator_traits<I>::difference_type
typedef _Distance difference_type;
//4. 同样以int为例,pointer就是 int*
typedef _Pointer pointer;
//5. 类型引用,以int为例,就是 int&,使得
typedef _Reference reference;
};
#if __cplusplus >= 201103L
//空模板
template<typename _Iterator, typename = __void_t<>>
struct __iterator_traits { };
//接收一个迭代器,将它的属性作为自己的属性(萃取)。_Iterator只声明类型,没有定义参数变量。
template<typename _Iterator>
struct __iterator_traits<_Iterator, __void_t<typename _Iterator::iterator_category,
typename _Iterator::value_type,
typename _Iterator::difference_type,
typename _Iterator::pointer,
typename _Iterator::reference>> {
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
//继承__iterator_traits
template<typename _Iterator>
struct iterator_traits : public __iterator_traits<_Iterator> { };
#else
//c++11之前的版本,直接定义
template<typename _Iterator>
struct iterator_traits {
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
#endif
//针对原生指针的traits偏特化版,也就是迭代器不是一个类,而只是一个指针,这种情况需要特化一下
template<typename _Tp>
struct iterator_traits<_Tp*> {
//注意在偏特化版本中,iterator_category的类型是random_access_iterator_tag
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef _Tp* pointer;
typedef _Tp& reference;
};
//针对 const 修饰的原生指针的偏特化版本
template<typename _Tp>
struct iterator_traits<const _Tp*>
{
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef const _Tp* pointer;
typedef const _Tp& reference;
};
//获取迭代器的类型
template<typename _Iter>
inline typename iterator_traits<_Iter>::iterator_category __iterator_category(const _Iter&) {
return typename iterator_traits<_Iter>::iterator_category();
}
//这里的_Iter_base很少被提及,作用不明
template<typename _Iterator, bool _HasBase>
struct _Iter_base {
typedef _Iterator iterator_type;
static iterator_type _S_base(_Iterator __it) {
return __it;
}
};
template<typename _Iterator>
struct _Iter_base<_Iterator, true> {
typedef typename _Iterator::iterator_type iterator_type;
static iterator_type _S_base(_Iterator __it) {
return __it.base();
}
};
#if __cplusplus >= 201103L
//重载决议,详情见:https://www.zhihu.com/question/31491227?sort=created
template<typename _InIter>
using _RequireInputIter = typename
enable_if<is_convertible<typename iterator_traits<_InIter>::iterator_category,
input_iterator_tag>::value>::type;
#endif
源码总览:stl_iterator_base_func
- 主要是定义advance(),distance()等函数,注意其中用到的传递调用
namespace std _GLIBCXX_VISIBILITY(default) {
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/*
函数:distance()
__distance函数是distance的底层函数,根据迭代器的不同有多个重载版本。对于distance而言,只需要两个__advance版本
在传递调用的作用下,除了RandomAccessIterator之外,其他的都和InputIterator操作相同,因此都调用input迭代器版本
*/
//__distance函数, InputIterator版本
template<typename _InputIterator>
inline typename iterator_traits<_InputIterator>::difference_type
__distance(_InputIterator __first, _InputIterator __last,
input_iterator_tag)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
//计算distance
typename iterator_traits<_InputIterator>::difference_type __n = 0;
while (__first != __last) {
++__first;
++__n;
}
return __n;
}
//__distance函数, RandomAccessIterator版本,可以直接相减
template<typename _RandomAccessIterator>
inline typename iterator_traits<_RandomAccessIterator>::difference_type
__distance(_RandomAccessIterator __first, _RandomAccessIterator __last,
random_access_iterator_tag)
{
// concept requirements
__glibcxx_function_requires(_RandomAccessIteratorConcept< _RandomAccessIterator>)
return __last - __first;
}
//distance的上层接口,只需要传入2个参数。按照STL规则,以最低阶的InputIterator接收参数
template<typename _InputIterator>
inline typename iterator_traits<_InputIterator>::difference_type
distance(_InputIterator __first, _InputIterator __last)
{
return std::__distance(__first, __last, std::__iterator_category(__first));
}
/*
函数:advance()
有3个版本的__advance(),分别是InputIterator,BidirectionalIterator,RandomAccessIterator
output迭代器,forward迭代器的__advane操作和input迭代器的操作相同,所以完全可以向上调用input迭代器的对应函数
*/
//__advance()函数,只读版本
template<typename _InputIterator, typename _Distance>
inline void __advance(_InputIterator& __i, _Distance __n, input_iterator_tag) {
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
_GLIBCXX_DEBUG_ASSERT(__n >= 0);
while (__n--)
++__i;
}
//__advance()函数,双向版本,允许回退
template<typename _BidirectionalIterator, typename _Distance>
inline void __advance(_BidirectionalIterator& __i, _Distance __n, bidirectional_iterator_tag) {
// concept requirements
__glibcxx_function_requires(_BidirectionalIteratorConcept<_BidirectionalIterator>)
if (__n > 0)
while (__n--)
++__i;
else
while (__n++)
--__i;
}
//__advance()函数,随机版本
template<typename _RandomAccessIterator, typename _Distance>
inline void __advance(_RandomAccessIterator& __i, _Distance __n, random_access_iterator_tag) {
// concept requirements
__glibcxx_function_requires(_RandomAccessIteratorConcept<_RandomAccessIterator>)
__i += __n;
}
//advance的上层接口
template<typename _InputIterator, typename _Distance>
inline void advance(_InputIterator& __i, _Distance __n) {
// concept requirements -- taken care of in __advance
typename iterator_traits<_InputIterator>::difference_type __d = __n;
std::__advance(__i, __d, std::__iterator_category(__i));
}
#if __cplusplus >= 201103L
//next的函数,前进n个,由advance实现,采用ForwardIterator,返回迭代器
template<typename _ForwardIterator>
inline _ForwardIterator next(_ForwardIterator __x, typename
iterator_traits<_ForwardIterator>::difference_type __n = 1) {
std::advance(__x, __n);
return __x;
}
//prev函数,后退n个,由advance实现,采用BidirectionalIterator
template<typename _BidirectionalIterator>
inline _BidirectionalIterator prev(_BidirectionalIterator __x,
typename iterator_traits<_BidirectionalIterator>::difference_type __n = 1) {
std::advance(__x, -__n);
return __x;
}
#endif // C++11
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
其他知识:__type_traits(SGI STL)
将迭代器萃取扩展到其他类型,就有了type_traits,并相应地定义了true_type和false_type
type_traits可以萃取任意类型的特性
除了这两个文件之外,还有一个stl_iterator.h文件,主要定义了各种运算符重载,多且杂,以后有时间再仔细看
除此之外,还有type_traits,char_traits,alloc_traits等