使用traits技术表现迭代器类型 iterator_category

1.STL的迭代器类型标识,和容器中的迭代器类型。

2.使用trait技术实现stl的advance功能。

3.迭代器trait中的其他类型定义。 

 

1.STL的迭代器类型标识,和容器中的迭代器类型。

 熟悉的迭代器类型,输入、输出、前向、双向、随机。

c++标准程序库分别提供专属的卷标结构(tag struct),一个空的结构体来标志具体是哪种类型迭代器。如下:

        //    ITERATOR STUFF (from <iterator>)// ITERATOR TAGS (from <iterator>)
struct input_iterator_tag{    // identifying tag for input iterators   
    };struct output_iterator_tag{    // identifying tag for output iterators
    };struct forward_iterator_tag: input_iterator_tag, output_iterator_tag{    // identifying tag for forward iterators  这些继承关系有有效的IS-A
    };struct bidirectional_iterator_tag: forward_iterator_tag{    // identifying tag for bidirectional iterators
    };struct random_access_iterator_tag: bidirectional_iterator_tag{    // identifying tag for random-access iterators};

而在每个容器中,就使用上述的tag struct标识自自身迭代器的类型,大概的思路是下面的样子,但真正源码实现复杂多。

// vector 容器 随机迭代器。list 容器 双向迭代器。
template<...> class vector{ public: class iterator{ public: typedef random_access_iterator_tag iterator_category;
     // 类型定义: vector<T>::iterator::iterator_category 就是 random_access_iterator_tag
     // 即类型里面还有一个类型, 而这个类型仅仅是用来标识 这个类是属于哪个类型的。 }; };template
<...> class list{ public: class iterator{ public: typedef bidirectional_iterator_tag iterator_category; }; };

 

2.使用trait技术实现stl的advance功能。

STL标准模版库={容器templates,迭代器templates(关联容器 和 算法),算法templates,工具性template如advance}。这里选择迭代器模版和Advance的实现来讲解trait技术。

 

先看看advance的用法:

// advance 函数签名
std::advance template
<class Iterator, class Distance>void advance (Iterator& it, Distance n);
// advance example
#include <iostream>     // std::cout
#include <iterator>     // std::advance
#include <list>         // std::listint main () {std::list<int> mylist;for (int i=0; i<10; i++) mylist.push_back (i*10);std::list<int>::iterator it = mylist.begin();std::advance (it,5); std::cout << "The sixth element in mylist is: " << *it << '\n';return 0;
}

advance内部操作时候,需要知道advance的迭代器类型,看有哪些可用操作,比如随机访问器可以直接+= -=操作,前向仅支持++,输入输出均不支持,例子中的list属于双向,支持++,--。

所以在advance内部需要在取得某种类型信息,即迭代器的类型,进行不同的实现。

 

如何取得类型信息呢,在1中其实我们已经定义了迭代器的类型,可以通过 ”容器类型::iterator::iterator_category“来获取类型信息。

但如果要支持内置类型,比如指针是一种随机迭代器类型,那么类型信息就不能放在类型内了,意味着类型内的嵌套类的方式不能工作,所以类型的信息必须位于类型自身之外。

 

trait标准技术是把它放进一个template,并进行一个偏特化版本,来实现迭代器所属类型trait。trait特性的意思 就有有关迭代器的相关特性。

// 即再封装一层,如果是用户自定义的,就直接获取内部定义的迭代器类型
// 如果是内置类型,就直接给设定成他所属的迭代器类型,用模版偏特化
// iterator_traits 
template<typename IterT> 
struct iterator_traits{ typedef typename IterT::iterator_category iterator_category; // 注意: 这里typename关键字 指示编译器解析 IterT::iterator_category 为一个类型
    ... 
};template<typename IterT>        //template 偏特化,针对内置指针 
struct iterator_traits<IterT*>{ typedef random_access_iterator_tag iterator_category; 
};

template<typename IterT>       
struct iterator_traits<const IterT*>{ typedef random_access_iterator_tag iterator_category; 
};
 

 

在advance的用法中,就可以使用 iterator_traits 类来判断是什么类型

// advance运行时确定使用哪种迭代器类型版本
template<typename IterT, typename DistT> void advance(IterT& iter, DistT d) { if (typeid(typename std::iterator_traits<IterT>::iterator_category) == typeid(std::random_access_iterator_tag)) { iter += d;} else if(前向迭代器类型){ if (d < 0){throw std::out_of_range("Negative distance");} while (d--) ++iter; }else if(等等其他类型)... }

 

使用重载函数的机制,在编译器就确定调用哪个迭代器类型的advance,以提高运行时效率。

// advance编译器确定使用哪种迭代器类型版本
template<typename IterT, typename DistT> 
void advance(IterT& iter, DistT d) 
{ doAdvance(iter, d, typename std::iterator_traits<IterT>::iterator_category()); 
}
// 比如 双向迭代器的函数 。重载doAdvance,实现不同的迭代器类型的具体操作。
// 可以看到迭代器类型仅仅是个重载的作用,使得重载机制得以运行,都不需要变量名。
void doAdvance(IterT& iter, DistT d, std::bidirectional_iterator_tag)          
{                                                                                                               if (d >= 0) {while (d--) ++iter;} else {while(d++) --iter;} 
} 

 

3.迭代器trait中的其他类型定义

 

 

template<class IterT>
struct iterator_traits{typedef typename IterT::iterator_category iterator_category;  // 迭代器的类型所属typedef typename IterT::value_type value_type;            // 迭代器所指对象的类型typedef typename IterT::difference_type difference_type;     // 迭代器之间的距离
 typedef typename IterT::pointer pointer;              // 迭代器所指内容的地址typedef typename IterT::reference reference;            // 迭代器所指之内容
};template<typename IterT>        //template 偏特化,针对内置指针 
struct iterator_traits<IterT*>{ typedef random_access_iterator_tag iterator_category; typedef IterT value_type; typedef ptrdiff_t difference_type ; 
typedef IterT
* pointer ; typedef IterT& reference ; };

 

 

另外,STL提供了一个 iterator类,如果每个新设计的迭代器都继承他,可保证符合STL所需的规范。

// TEMPLATE CLASS iterator
template<class _Category,class _Ty,class _Diff = ptrdiff_t,class _Pointer = _Ty *,class _Reference = _Ty&>struct iterator{    // base type for iterator classes
    typedef _Category iterator_category;typedef _Ty value_type;typedef _Diff difference_type;typedef _Pointer pointer;typedef _Reference reference;};

 

 

 

整理自 effective C++ 条款 47:使用traits classes表现类型信息

转载于:https://www.cnblogs.com/fulina/p/7058288.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/429181.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

外部仓库_仓库主要作业流程和WMS作业优化方案

仓库在人们眼中一直是低效、高成本的地方&#xff0c;即便是增加人手也很难做好仓库管理。那么我们应该采取哪些方式来管理&#xff0c;才能做到降本增效呢&#xff1f;首先我们需要先了解仓库主要作业流程及在作业中存在的痛点。1入库流程a.商品SKU太多&#xff0c;部分形状相…

java IO流(上)

1.字节流 1.1 IO流概述和分类【理解】 1.IO流介绍 IO&#xff1a;输入/输出(Input/Output)流&#xff1a;是一种抽象概念,是对数据传输的总称.也就是说数据在设备间的传输称为流,流的本质是数据传输IO流就是用来处理设备间数据传输问题的.常见的应用: 文件复制; 文件上传; 文…

java类与对象实验报告心得体会_第四周课程总结与实验报告(Java简单类与对象)...

1.写一个名为Rectangle的类表示矩形。其属性包括宽width、高height和颜色color&#xff0c;width和height都是double型的&#xff0c;而color则是String类型的。要求该类具有&#xff1a;(1) 使用构造函数完成各属性的初始赋值(2) 使用get…()和set…()的形式完成属性的访问及修…

《科技之巅2》序——机器智能数据智能:工具之王

原文链接 “凡是过去&#xff0c;皆为序曲。”——莎士比亚 通过不断发明工具&#xff0c;人类科技指数级进化。语言汇聚原始部落&#xff0c;马镫开启了中世纪的欧洲文明&#xff0c;“高产种子”引发人口爆炸&#xff0c;蒸汽机创造工业文明&#xff0c;大规模集成电路激活数…

一、java面向对象基础

1. 类和对象 面向对象和面向过程的思想对比 : ​ 面向过程 &#xff1a; 是一种以过程为中心的编程思想&#xff0c;实现功能的每一步&#xff0c;都是自己实现的 ​ 面向对象 &#xff1a; 是一种以对象为中心的编程思想&#xff0c;通过指挥对象实现具体的功能 1.1 类和对…

quint32转化为qstring_QT中字符串QString类型的转换

把QString转换为 double类型方法1.QString str"123.45";double valstr.toDouble(); //val123.45方法2.很适合科学计数法形式转换bool ok;double d;dQString("1234.56e-02").toDouble(&ok); //oktrue;d;12.3456.把QString转换为float形1.QString str&qu…

Linux 普通用户拿到root权限及使用szrz命令上传下载文件

1.如何拿到root权限 在shell里如果看到你的命令输入行最前面显示的是 $符号&#xff0c;说明目前账号只有系统的普通权限。 输入&#xff1a;sudo su 这时能看到shell的输入行最前面已经显示的是#号&#xff0c;说明已经是root权限了。 2.安装szrz命令 首先需要在yum的下载源里…

pythom打包文件太大_从SQL注入到整站打包与本地搭建

一、前言如题&#xff0c;由于是在已知有一处sql注入的情况下才接手进行的后续操作&#xff0c;因此前面信息搜集则一笔带过。二、信息搜集目标是个本地的传销站点其大致信息为IISASP.NET安全狗、腾讯云。三、Bypass Sql3.1 Fuzz空格 error 加号 未拦截 等号 er…

二、常用API——String类和StringBuilder类

1.API 1.1 API概述-帮助文档的使用 什么是API ​ API (Application Programming Interface) &#xff1a;应用程序编程接口 java中的API ​ 指的就是 JDK 中提供的各种功能的 Java类&#xff0c;这些类将底层的实现封装了起来&#xff0c;我们不需要关心这些类是如何实现的&a…

运算符的优先级

运算符的优先级和结合性 优 先 级 运 算 符 含 义 运算对象个数 结合方向 1 () 圆括号 自左向右 [] 下标运算符 −> 指向结构体成员运算符 . 结构体成员运算符 2 ! 逻辑非运算 1&#xff08;单目&#xff09; 自右向左 &#xff5e; 按位取反…

iphone复制不能全选_忘记Apple ID密码,如何直接在 iPhone 上更改?

最近有不少同学问我&#xff0c;如果忘记了 Apple ID 的密码&#xff0c;怎么能直接在 iPhone 上修改&#xff1f;别急&#xff0c;我现在就教你如果之前已经在 iPhone 上登录过你的账户&#xff0c;并且已经将 iPhone 设置为「受信任设备」&#xff0c;那么就可以直接在 iPhon…

三、集合基础——ArrayList集合与简单学生管理系统

1.ArrayList 集合和数组的区别 : ​ 共同点&#xff1a;都是存储数据的容器 ​ 不同点&#xff1a;数组的容量是固定的&#xff0c;集合的容量是可变的 1.1 -ArrayList的构造方法和添加方法 public ArrayList()创建一个空的集合对象public boolean add(E e)将指定的元素追…

网上看了很多教程&#xff0c;写的都不细致&#xff0c;或者我理解不够透彻&#xff0c;一步一步操作下来&#xff0c;总是错误百出。好不容易成功一次&#xff0c;现将完整过程记录如下 安装VS Code sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make sudo apt-get upd…

nginx 上传 文件超时设置_Nginx在高并发下的性能优化点!有这篇就够了!

点击上方“java进阶架构师”&#xff0c;选择右上角“置顶公众号”20大进阶架构专题每日送达前面几周&#xff0c;讲过Nginx的日志配置&#xff1a;Nginx | 超详细&#xff01;Nginx 日志配置实践&#xff0c;然后也讲了Nginx的进程模型&#xff0c;底层原理等&#xff1a;Ngin…

四、java面向对象高级——分类和分包思想、static关键字

1.案例驱动模式 1.1案例驱动模式概述 (理解) 通过我们已掌握的知识点,先实现一个案例,然后找出这个案例中,存在的一些问题,在通过新知识点解决问题 1.2案例驱动模式的好处 (理解) 解决重复代码过多的冗余,提高代码的复用性解决业务逻辑聚集紧密导致的可读性差,提高代码的可…

五、java面向对象高级——java中的继承和抽象类

1. 继承 1.1 继承的实现&#xff08;掌握&#xff09; 继承的概念 继承是面向对象三大特征之一&#xff0c;可以使得子类具有父类的属性和方法&#xff0c;还可以在子类中重新定义&#xff0c;以及追加属性和方法 实现继承的格式 继承通过extends实现格式&#xff1a;class 子…

实现进程守护 脚本命令

echo off ::检测时间间隔&#xff0c;单位&#xff1a;秒 set _interval3::需要守护的进程名称 set _processNameC:\Users\Administrator\Desktop\XunLeiX\Release\Quickstart.exe ::需要守护的进程启动命令 set _processCmdC:\Users\Administrator\Desktop\XunLeiX\Releas…

万丰科技机器人排名_2020年全国机器人企业数量大排名(省份榜|9月)

点击上方兔子岛关注浩然哥原创不易 欢迎分享转载请注明出处作者&#xff1a;浩然哥2020年全国机器人企业数量大排名省份榜|9月大家好&#xff0c;《全国机器人企业数量大排名》又和大家见面了。本期是2020年省份榜的9月份榜单。2020年年底了&#xff0c;近期7月、9月、11月&am…

grafana授权公司内部邮箱登录 ldap配置

vi /etc/grafana/grafana.ini &#xff08;文件不一定是这个噢&#xff0c;看自己启动服务的配置文件&#xff09; 修改配置&#xff1a; [auth.ldap] enabled true config_file /etc/grafana/ldap.toml &#xff08;文件路径不一定是这个噢&#xff0c;看自己的配置文…

六、java面型对象高级——接口和多态

1.接口 1.1黑马信息管理系统集合改进 (应用) 使用数组容器的弊端 容器长度是固定的&#xff0c;不能根据添加功能自动增长没有提供用于赠删改查的方法 优化步骤 创建新的StudentDao类&#xff0c;OtherStudentDao 创建ArrayList集合容器对象 OtherStudentDao中的方法声明&a…