迭代器概念与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技术可以用来获得一个 类型 的相关信息的. 首先假如有以下一个泛型的迭代器类 ...
随机推荐
- TCP/IP与Http与socket的关系
1 理清概念: TCP/IP是一个大的协议族(只不过TCP和IP是super star所以就这么命名了),它包括了: 应用层协议:FTP.HTTP.TELNET.SMTP.DNS(协议): 传输层协议 ...
- msxml3.dll 错误 '800c0005' 系统错误: -2146697211。
asp网站 因为这个问题,困扰自己好多次,还重装过两次服务器系统,非常的麻烦,这次终于找到了问题所在,记录下来,方便以后查看. 服务器症状: 1.服务器上的IE浏览器不能访问外网: 2.set htt ...
- linux使用crontab实现PHP执行计划定时任务
linux使用crontab实现PHP执行计划定时任务 前几天写过一篇文章,利用单纯的php实现定时执行任务,但是效率不佳,对于linux来说用crontab实现更加合理 首先说说cron,它是一个l ...
- Clickhouse DDL&DML
(1)添加列: alter table [db.]table_name add column column_name [type] [default_expr] [after name_after] ...
- map 用法
map 是一种关联容器, 提供一对一的关联, 关联的形式为: KEY----VALUE 关键字不重复.multimap与map类似,但是允许关键字重复 即:关键字和与之对应的值 关键字起到索 ...
- CAD使用GetXData读数据(com接口)
主要用到函数说明: MxDrawEntity::GetXData 返回实体的扩展数据. c#代码实现如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1 ...
- POJ2152 Fire (树形DP)
题意:n个城市n-1条边 组成一棵树 在每个城市修建消防站会有一个花费costi 每个城市能防火当且仅当地图上距离他最近的消防站距离小于di 问如何修建消防站 使地图上所有的城市都有预防火灾的能力 ...
- Spring Security 介绍与Demo
一.Spring Security 介绍 Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块的默认技术选型.我们仅需引入spring-boot-s ...
- python3.x Day2 购物车程序练习
购物车程序: 1.启动程序后,输入用户名密码后,如果是第一次登录,让用户输入工资,然后打印商品列表 2.允许用户根据商品编号购买商品 3.用户选择商品后,检测余额是否够,够就直接扣款,不够就提醒 4. ...
- Android jdbc连接mysql报错解决方案 (Communications link failure)
最近调试安卓连接mysql真是心态爆炸,快两天才搞出来.以下整理一些常见问题. 检查manifest文件里网络权限是否打开 检查数据库IP是否有问题(包括一些沙雕错误,比如是不是在ip首或尾多了个空格 ...