//迭代器是一种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编程技法的更多相关文章

  1. STL源码分析读书笔记--第三章--迭代器(iterator)概念与traits编程技法

    1.准备知识 typename用法 用法1:等效于模板编程中的class 用法2:用于显式地告诉编译器接下来的名称是类型名,对于这个区分,下面的参考链接中说得好,如果编译器不知道 T::bar 是类型 ...

  2. 迭代器iterator和traits编程技法

    前言 这段时间研读SGI-STL-v2.91源码,并提炼核心代码自己实现一遍,感觉受益颇深.觉得有必要写一些文章记录下学习过程的思考,行文旨在总结,会大量参考侯捷<STL源码剖析>的内容. ...

  3. 迭代器(iterator) 与 traits 编程技法

    看了候哥的<STL源码剖析>的迭代器那一章,在这里将思路稍微疏理一下 迭代器 迭代器模式的定义:提供一种方法,在不需要暴露某个容器的内部表现形式情况下,使之能依次访问该容器中的各个元素. ...

  4. STL——迭代器与traits编程技法

    一.迭代器 1. 迭代器设计思维——STL关键所在 在<Design Patterns>一书中对iterator模式定义如下:提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素 ...

  5. 【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

    大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub : https://github.com/rongweihe/Mor ...

  6. STL源码--iterator和traits编程技法

    第一部分 iterator学习 STL iterators定义: 提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达方式. 任何iteartor都应该提供5 ...

  7. STL Traits编程技法

    traits编程技法大量运用于STL实现中.通过它在一定程度上弥补了C++不是强型别语言的遗憾,增强了C++关于型别认证方面的能力. traits编程技法是利用“内嵌型别”的编程技法和编译器的temp ...

  8. STL中的Traits编程技法

    最近在看读<STL源码剖析>,看到Traits编程技法这节时,不禁感慨STL源码作者的创新能力.那么什么是Traits编程技法呢?且听我娓娓道来: 我们知道容器的许多操作都是通过迭代器展开 ...

  9. [转]Traits 编程技法+模板偏特化+template参数推导+内嵌型别编程技巧

    STL中,traits编程技法得到了很大的应用,了解这个,才能一窥STL奥妙所在. 先将自己所理解的记录如下: Traits技术可以用来获得一个 类型 的相关信息的. 首先假如有以下一个泛型的迭代器类 ...

随机推荐

  1. VS中设置xml智能提示

    1.第一步:将xsd文件复制到VS的安装目录下 默认安装目录为:C:\Program Files (x86)\Microsoft Visual Studio 12.0\Xml\Schemas 2.第二 ...

  2. RabbitMQ指南之五:主题交换器(Topic Exchange)

    在上一章中,我们完善了我们的日志系统,用direct交换器替换了fanout交换器,使得我们可以有选择性地接收消息.尽管如此,仍然还有限制:不能基于多个标准进行路由.在我们的日志系统中,我们可能不仅希 ...

  3. LN : leetcode 263 Ugly Number

    lc 263 Ugly Number lc 263 Ugly Number Write a program to check whether a given number is an ugly num ...

  4. MySql(五)select排序查询

    举个栗子/**查询员工信息,要求工资按照从高到低进行排序(默认升序)**/SELECT * FROM employees ORDER BY salary ASC;/**方法2:**/SELECT * ...

  5. blender_(uv应用)................http://digitalman.blog.163.com/blog/static/23874605620174172058299/

    轻松学习Blender基础入门之九:UV-1 2017-06-21 14:24:49|  分类: Blender |举报 |字号 订阅     下载LOFTER 我的照片书  |   [前言]     ...

  6. 类似倒圆角方法输入半径选择实体 kword

    ads_name ename; ads_point adspt; acedInitGet(NULL, TEXT("R")); while (1) { int rc = acedEn ...

  7. Xamarin View获取属性的绑定信息

    public static Binding GetBinding( BindableObject self, BindableProperty property) { var methodInfo = ...

  8. Xamarin绑定ios静态库

    以下是官方的步骤介绍,我就不再一步步解释了 https://docs.microsoft.com/zh-cn/xamarin/ios/platform/binding-objective-c/walk ...

  9. Vue2.0 —生命周期和钩子函数

    vue生命周期简介 咱们从上图可以很明显的看出现在vue2.0都包括了哪些生命周期的函数了. 生命周期探究 对于执行顺序和什么时候执行,看上面两个图基本有个了解了.下面我们将结合代码去看看钩子函数的执 ...

  10. ThinkPHP---案例1登录登出和添加部门

    配置文件分3类:系统配置文件,分组配置文件,应用配置文件 ①系统配置文件ThinkPHP/Conf/convention.php: ②分组 / 模块 /平台配置文件Home/Conf/config.p ...