文章目录
- 一、前置学习
- 1)萃取
- (1)迭代器所指对象的类型-value_type
- <1>第一个限制-返回参数需要指明迭代器的value_type
- <2>第二个限制坑点-不是所有迭代器都是class type,原生指针就不是
- <3>第三个限制坑点-如果针对"指向常数对象的指针(point-to-const)"获得的值带const不是我们期望的
- (2)最常用到的迭代器类型有五种:
- <1>value_type
- <2>difference_type
- <3>pointer_type
- <4>reference_type
- <5>iterator_category
一、前置学习
1)萃取
(1)迭代器所指对象的类型-value_type
- 备注
因为迭代器需要知道所指向对象的类型
<1>第一个限制-返回参数需要指明迭代器的value_type
迭代器所指对象的类型,称为该迭代器的value type,上述的参数类型推导只可适用于推导函数参数,却不能作为函数的返回值
- 解决办法
声明内嵌类型
template <class T>
struct MysIter
{
typedef T value_type; //内嵌类型声明
T* Ptr;
MyIter(T * p=0):ptr(p){}
T& operator*() const {return *ptr};
//...
};
template <class T>
typename I::value_type; //这一整行是func的返回值类型
func(I ite)
{
return *ite;
}
//...
MyIter<int> ite(new int(8));
cout<<func(ite); //输出8
- 注意点
func()的含绘制必须加上关键词typename,因为T是一个template参数,但它被编译器特例化之前,编译器对T一无所知。关键词typename的作用是告诉编译器这是一个类型,才能通过编译
<2>第二个限制坑点-不是所有迭代器都是class type,原生指针就不是
不是所有迭代器都是class type,原生指针就不是,可不是class type,就无法为他定义内嵌类型,但STL(及整个泛型思维)绝对必须接受原生指针作为一种迭代器,所以上面还不够。
- 解决坑点
方法:偏特化(template partial specialization)
- 思想方法
原生指针并非class,因此无法为他们定义内嵌类型,现在,可以针对迭代器template参数为指针
设置特化版的迭代器了
template <class I>
struct iterator_traits // traits 意为特性
{
typedef typename I::value_type value_type;
};
这个所谓traits意义是:如果I定义
有自己的value_type
,那么通过这个traits的作用,萃取出来的value_type就是I::value_type,换句话说,如果I有自己的value_type,先前哪个func()可以改写成这样:(多了这一层,那么traits可以拥有特例化版本
)
template <class I>
typename iterator_traits<I>::value_type //这一样是返回值类型
func(I ite)
{
return *ite;
}
现在做特例化版本如下:
template <class T>
struct iterator_traits<T*> //偏特化版本,迭代器是原生指针
{
typedef T value_type;
};
- 结果
于是,原生int*虽然不是一种class type,也可以通过traits取其value_type,这就解决了先前的问题
<3>第三个限制坑点-如果针对"指向常数对象的指针(point-to-const)"获得的值带const不是我们期望的
- 举例
iterator_traits<const int*>::value_type 获得的是const int 而非int
- 解决方法
只需要设计一个特例化版本
template <class T>
struct iterator_traits<const T*> //偏特化-当迭代器是point-to-const版本时,萃取出来T,
//而非const T
{
typedef T value_type;
};
(2)最常用到的迭代器类型有五种:
<1>value_type
- 概念介绍
代指迭代器所指对象的类型 - 意义
任何一个跟stl完美搭配的class,都应该定义自己的value_type内嵌类型
<2>difference_type
-
概念介绍
表示两个迭代器之间的距离,因此它可以用来表示一个容器的最大容量,因为对于连续的容器而言,头尾之间的距离就是最大容量 -
举例用法
若一个泛型算法提供计数功能,例如STL的count(),其返回值就必须使用迭代器的difference_type
template<class I,class T>
typename iterator_traits<I>::difference_type //这一整行是返回值类型
count(I first,I last ,const T& value)
{
typename iterator_traits<I>::difference_type n = 0;
for(;first != last ;++first)
if(*first == value)
++n;
return n;
}
- difference_type针对原生指针的两种特化(以C++内建的ptrdiff_t作为原生指针的difference_type)
template<class T>
struct iterator_traits
{
...
typedef typename I::difference_type difference_type;
};
①针对原生指针设计的偏特化版本
template<class T>
struct iterator_traits<T*>
{
...
typedef ptrdiff_t difference_type;
};
②针对原生的pointer-to-const二设计的偏特化
template<class T>
struct iterator_traits<const T*>
{
...
typedef ptrdiff_t difference_type;
};
- 总结
现在当我们需要任何迭代器I的difference_type,可以这么写
typename iterator_traits<I>::difference_type;
<3>pointer_type
- 作用
传回一个pointer,指向迭代器所指之物 - 举例
Item& operator*() const {return *ptr;} //这个就是reference_type
Item* operator->() const {return ptr;} //这个就是pointer_type
- 把reference_type和pointer_type都加入到traits里面
template <class I>
struct iterator_traits
{
...
typedef typename I::pointer pointer;
typedef typename I::reference reference;
};
- 针对原生指针的两种特化
①针对原生指针的偏特化
template <class I>
struct iterator_traits<T*>
{
...
typedef typename T* pointer;
typedef typename T& reference;
};
②针对原生的pointer-to-const的偏特化
template <class I>
struct iterator_traits<const T*>
{
...
typedef typename T* pointer;
typedef typename T& reference;
};
<4>reference_type
- 原理
当我们要返回可修改的迭代器mutable iterator时,获得应该是一个左值,因为右值不允许赋值操作(assignment),左值才允许。 - 解决方法
C++中,函数要返回左值,都是以传引用的凡是。托value_type是T,那么*p的类型不该是T,而是T&;同理,若是constant iterator,*p的类型那就是const T&,而不是const T
<5>iterator_category
-
迭代器分类(根据
移动特性和操作
)
①Input iterator: 只读的迭代器对象
②Output iterator: 只写的迭代器对象
③Forward iterator:在此迭代器上可进行读写操作
④Bidirectional iterator: 可双向移动
⑤Random Access iterator:前四种值提供一部分指针算数能力(举例:前三种支持operator++,第四种再加上operator–),第五种则覆盖所有指针算数能力,包括:p+n,p-n,p[n],p1-p2,p1<p2 -
迭代器的概念和强化
最高等级的迭代器类型并不代表最佳