iterator:
- iterator_category 五种迭代器类型标记
这里共有5种迭代器标记(代表五种类型的迭代器,比如vector就是forward类型的,list是bidirectorational类型的)
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 {};
2.根据五种迭代器类型标记,分别声明五种对应的迭代器:
template <class _Tp, class _Distance> struct input_iterator {
typedef input_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Tp* pointer;
typedef _Tp& 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 _Tp, class _Distance> struct forward_iterator {
typedef forward_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Tp* pointer;
typedef _Tp& reference;
};
template <class _Tp, class _Distance> struct bidirectional_iterator {
typedef bidirectional_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Tp* pointer;
typedef _Tp& reference;
};
template <class _Tp, class _Distance> struct random_access_iterator {
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Tp* pointer;
typedef _Tp& reference;
};
// 用户自己的写的迭代器最好继承此 std::iterator
#ifdef __STL_USE_NAMESPACES
template <class _Category, class _Tp, class _Distance = ptrdiff_t,
class _Pointer = _Tp*, class _Reference = _Tp&>
struct iterator {
typedef _Category iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
};
#endif /* __STL_USE_NAMESPACES */
理论上有这些iterator,在我们使用标准算法库的时候,只需要告诉该算法对应的iterator_category即可,
那traits的作用是什么呢?这里要提到的是,除list/vector/map等常用容器有对应的iterator,原始指针也
是一种iterator,但是原始指针并没有iterator_category标记,也就无法告诉算法当前iterator是不是原始
指针。这时就需要使用traits了。
traits:
traits其实就是一层封装,利用了泛型模板和偏特化模板类将原始指针和各个容器的iterator类型封装出统一
接口,这样就可以告诉算法传进去的参数到底是什么类型的iterator。
// traits 获取各个迭代器的特性(相应类型)-----类型特性类,这是泛型类模板
template <class _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; // 被迭代类型的引用类型
};
// 针对原生指针(native pointer)而设计的 traits 偏特化版
template <class _Tp>
struct iterator_traits<_Tp*> {
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type; // C++ 内建的 ptrdiff_t 类型
typedef _Tp* pointer;
typedef _Tp& reference;
};
// 针对原生之 pointer-to-const 而设计的 traits 偏特化版
template <class _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;
};
当iterator是原始指针的时候,就会使用偏特化的版本,这样对于算法来说,上层传的iterator类型就统一了。
traits源码中还有三个重要函数,这里不少小伙伴看了应该都会有疑惑,不知道这些函数的作用,我们先看看函数,然后再看他们的作用:
// 决定某个迭代器的类型-category 类别
template <class _Iter>
inline typename iterator_traits<_Iter>::iterator_category
__iterator_category(const _Iter&)
{
typedef typename iterator_traits<_Iter>::iterator_category _Category;
return _Category();
}
// 决定某个迭代器的类型-difference type
template <class _Iter>
inline typename iterator_traits<_Iter>::difference_type*
__distance_type(const _Iter&)
{
return static_cast<typename iterator_traits<_Iter>::difference_type*>(0);
}
// 决定某个迭代器的类型-value_type
template <class _Iter>
inline typename iterator_traits<_Iter>::value_type*
__value_type(const _Iter&)
{
return static_cast<typename iterator_traits<_Iter>::value_type*>(0);
}
// 封装 __iterator_category 函数
template <class _Iter>
inline typename iterator_traits<_Iter>::iterator_category
iterator_category(const _Iter& __i) { return __iterator_category(__i); }
// 封装 __distance_type 函数
template <class _Iter>
inline typename iterator_traits<_Iter>::difference_type*
distance_type(const _Iter& __i) { return __distance_type(__i); }
// 封装 value_type 函数
template <class _Iter>
inline typename iterator_traits<_Iter>::value_type*
value_type(const _Iter& __i) { return __value_type(__i); }
#define __ITERATOR_CATEGORY(__i) __iterator_category(__i)
#define __DISTANCE_TYPE(__i) __distance_type(__i)
#define __VALUE_TYPE(__i) __value_type(__i)
下面看看这几个函数如何使用:
//两个重载的__copy函数,依据参数的类型被调用
//函数定义的最后两个参数只写类型,用来占位,只做类型匹配。
template <class _InputIter, class _OutputIter, class _Distance>
inline _OutputIter __copy(_InputIter __first, _InputIter __last,
_OutputIter __result,
input_iterator_tag, _Distance*)
{
for ( ; __first != __last; ++__result, ++__first)
*__result = *__first;
return __result;
}
template <class _RandomAccessIter, class _OutputIter, class _Distance>
inline _OutputIter
__copy(_RandomAccessIter __first, _RandomAccessIter __last,
_OutputIter __result, random_access_iterator_tag, _Distance*)
{
for (_Distance __n = __last - __first; __n > 0; --__n) {
*__result = *__first;
++__first;
++__result;
}
return __result;
}
//重点在于__copy_aux2函数,__ITERATOR_CATEGORY(__first)和__DISTANCE_TYPE(__first)可以匹配对应的
random_access_iterator_tag, _Distance*类型,从而做到调用不同__copy函数。
template <class _InputIter, class _OutputIter>
inline _OutputIter __copy_aux2(_InputIter __first, _InputIter __last,
_OutputIter __result, __false_type) {
return __copy(__first, __last, __result,
__ITERATOR_CATEGORY(__first),
__DISTANCE_TYPE(__first));
}
最后traits的用法远不止于此,但是基本上是按照这个规则来实现,即模板的泛化与特化。