迭代器概念与traits编程技法
//迭代器是一种smart pointer
template<typename T>
class ListItem
{
public:
T value() const
{
return _value;
}
ListItem* next() const
{
return _next;
}
private:
T _value;
ListItem *_next;
}; template<class T>
class List
{
public:
void insert_front(T value);
void insert_end(T value);
void display(ostream&os = cout)const;
private:
ListItem<T>*_end;
ListItem<T>*_front;
long _size;
}; //为链表设计一个迭代器,要设计迭代器,必须要对容器有足够的了解
//所以list和对应的迭代器的设计都由list的设计者实现,从而封装实现细节
template<class Item>
struct ListIter
{
Item *ptr;//保持与容器之间的一个联系,ptr是list结点指针
ListIter(Item *p = ) :ptr(p){} //迭代器行为类似指针,其中最常见的操作是内容提领和成员访问
//所以要对operator*和operator->进行重载,可参考auto_ptr的实现
Item& operator*()const
{
return *ptr;
}
//重构->,返回值必须为一个指针或可以应用 -> 操作的类型
Item* operator->()const
{
return ptr;
}
// 前增量,返回引用(迭代器对象)
ListIter& operator++()
{
ptr = ptr->next();
return *this;
}
// 后增量,返回值
ListIter operator++(int)
{
ListIter tmp = *this;
++*this;// 利用前面对++的重载
return tmp;
} bool operator==(const ListIter& i)const
{
return ptr == i.ptr;
}
bool operator!=(const ListIter& i)const
{
return ptr != i.ptr;
}
};
注意operator *和operator->的实现,operator* 返回一个引用,operator->返回值必须为一个指针或可以应用 -> 操作的类型
如何获取迭代器所指对象的类型,即如何实现类型萃取?
可以定义一个类模板用于萃取迭代器特性,模板参数是迭代器类型。迭代器内部定义一个typedef表示迭代器所指对象类型,然后在萃取模板类中使用
typedef typename I::value_type value_type;
提取类型。由于原生指针不是class,无法定义value_type,可以对萃取模板类生成特化版本。
// 如何获取迭代器所指对象的类型
template<class T>
struct MyIter
{
typedef T value_type;//迭代器所指对象类型
T *ptr;
//....
}; template<class I>
// 函数func接受一个迭代器参数,返回值是迭代器所指对象类型
// typename告诉编译器I::value_type是一个类型(嵌套从属名称),使得能够通过编译
// 此处存在问题:如果I不是个class type,就无法定义value_type
// 可以封装类型萃取类,然后针对原生指针做偏特化处理
typename I::value_type func(I ite)
{
return *ite;
} //类模板用于萃取迭代器特性,I为迭代器类型
template<class I>
struct iterator_traits
{
typedef typename I::value_type value_type;//针对class
};
//原生指针不是class,无法定义value_type
//traits可以拥有特化版本,T *为原生指针int *,则T也就是value_type为int
template<class T>
struct iterator_traits<T*>
{
typedef T value_type;//针对原生指针
}; // 萃取机完整版本(最常用到的迭代器五种类型)
// 若使容器能与STL兼容,必须要为容器的迭代器定义以下五种相应型别
template <class I>
struct iterator_traits
{
typedef typename I::iterator_category iterator_category;// 迭代器类型
typedef typename I::value_type value_type;// 迭代器所指对象的类型
typedef typename I::difference_type difference_type;// 两个迭代器之间的距离
typedef typename I::pointer pointer;// 迭代器所指对象的指针
typedef typename I::reference reference;// 迭代器所指对象的引用
}; /*
迭代器有五种类型,Input Iterator,output Iterator,Forward Iterator只支持++,Biderectional Iterator支持++、--,Random Access Iterator支持
所有运算,效率最高
*/
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 InputIterator,class Distance>
inline void _advance(InputIterator& i, Distance n, input_iterator_tag)
{
while (n--)
i++;
}
//下面四个函数类似,不再详述
//对外开放的接口, iterator_traits<InputIterator>::iterator_category()将产生一个暂时对象,编译器根据对象
//类型决定调用哪一个_advance重载函数
//STL一个命名规则:以算法所能接受的最低阶迭代器类型来为其迭代器类型参数命名
template<class InputIterator,class Distance>
inline void advance(InputIterator& i, Distance n)
{
_advance(i, n, iterator_traits<InputIterator>::iterator_category());
}
为了符合规范,任何迭代器都应该提供五个内嵌类型,以用于traits萃取,否则可能无法与其他STL组件顺利搭配。STL提供了一个iterators class如下,可让每个新设计的迭代器都继承自它。
//ptrdiff_t为c++内建类型,定义于<cstddef>
template <class Category,class T,class Distance=ptrdiff_t,class Pointer=T*,class Reference=T&>
struct iterator
{
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
};
迭代器概念与traits编程技法的更多相关文章
- STL源码分析读书笔记--第三章--迭代器(iterator)概念与traits编程技法
1.准备知识 typename用法 用法1:等效于模板编程中的class 用法2:用于显式地告诉编译器接下来的名称是类型名,对于这个区分,下面的参考链接中说得好,如果编译器不知道 T::bar 是类型 ...
- 迭代器iterator和traits编程技法
前言 这段时间研读SGI-STL-v2.91源码,并提炼核心代码自己实现一遍,感觉受益颇深.觉得有必要写一些文章记录下学习过程的思考,行文旨在总结,会大量参考侯捷<STL源码剖析>的内容. ...
- 迭代器(iterator) 与 traits 编程技法
看了候哥的<STL源码剖析>的迭代器那一章,在这里将思路稍微疏理一下 迭代器 迭代器模式的定义:提供一种方法,在不需要暴露某个容器的内部表现形式情况下,使之能依次访问该容器中的各个元素. ...
- STL——迭代器与traits编程技法
一.迭代器 1. 迭代器设计思维——STL关键所在 在<Design Patterns>一书中对iterator模式定义如下:提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素 ...
- 【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法
大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub : https://github.com/rongweihe/Mor ...
- STL源码--iterator和traits编程技法
第一部分 iterator学习 STL iterators定义: 提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达方式. 任何iteartor都应该提供5 ...
- STL Traits编程技法
traits编程技法大量运用于STL实现中.通过它在一定程度上弥补了C++不是强型别语言的遗憾,增强了C++关于型别认证方面的能力. traits编程技法是利用“内嵌型别”的编程技法和编译器的temp ...
- STL中的Traits编程技法
最近在看读<STL源码剖析>,看到Traits编程技法这节时,不禁感慨STL源码作者的创新能力.那么什么是Traits编程技法呢?且听我娓娓道来: 我们知道容器的许多操作都是通过迭代器展开 ...
- [转]Traits 编程技法+模板偏特化+template参数推导+内嵌型别编程技巧
STL中,traits编程技法得到了很大的应用,了解这个,才能一窥STL奥妙所在. 先将自己所理解的记录如下: Traits技术可以用来获得一个 类型 的相关信息的. 首先假如有以下一个泛型的迭代器类 ...
随机推荐
- 292 Nim Game Nim游戏
您和您的朋友,两个人一起玩 Nim游戏:桌子上有一堆石头,每次你们轮流拿掉 1 到 3 块石头. 拿掉最后一块石头的人就是胜利者.由您来开局.你们两个都是聪明人,相信都有最佳的游戏策略. 请编写一个函 ...
- kali中的APT软件包处理工具(apt-get)、Debian软件包管理器(dpkg)、源代码压缩和Nessus安装实用指南
写在前面的话 能看懂此博客的朋友,深信你有一定的Kali基础了. 使用APT软件包处理工具(apt-get).Debian软件包管理器(dpkg)来维护.升级和安装自定义及第三方应用程序 APT软件包 ...
- 15 C#中的条件执行,if else
在这一节的练习中,给大家介绍C#编程中的一个重要部分,条件执行.也就是If else语句.我们现实生活中的很多复杂的推理都可以用这个语法实现. If else语句的常规的样子,如下面所示. if (测 ...
- Microsoft SQL Server学习(四)--约束
SQLServer - 约束 主要是为了保证数据库中的数据一致性.有效性.准确性, 从而提高了数据库中数据的正确性 一.约束的分类 在SQLserver中,约束分三种不同类型 1.实体约束 实提约束是 ...
- Tcl之Read files for synthesis
The following file is to read all design files into syntehsis tool automatically, like Cadence RTL C ...
- vue-cli的项目加入骨架屏
在原生APP中我们经常可以看到,打开app时候,内容还没出来,app会被别的内容替代,这样很好的提升了用户体验.那么在webApp中,我们如何避免白屏的尴尬情况呢?可以通过 vue-skeleton- ...
- post请求重定向到get请求问题
springMVC默认重定向是get请求,我在方法注解中没有指定method是post还是get请求,这样就可以接收到post重定向来的请求,也可以接收到页面传来的get请求,如果要传参,可以使用mo ...
- ListView常用属性 (2012-01-12 17:20:27)
比较特别的属性,通过设置这样的属性可以做出更加美观的列表.stackFromBottom——设置该属性之后你最新条目就会显示你列表的最下面,值为true和false,如android:stackFro ...
- type、object、class之间的关系
class Foo: pass print(type(int)) # <class 'type'> print(type(str)) # <class 'type'> prin ...
- sectional data interpolation in Tecplot
$!Varset |NumLoop|= $!Loop |NumLoop| $!Varset |num|=(|Loop|*+) $!RotateData ZoneList = [] Angle = |n ...