《Effective C++》再次探索traits技法
首先介绍C++标准程序库中的五种迭代器,关于这个可以看我的另一个笔记:http://blog.csdn.net/m0_37316917/article/details/70053513。
对于这五种分类,C++标准程序库分别提供专属的标志结构加以确认:
struct input_iterator_tag{};
struct output_iterator_tag{};
struct forward_iterator_tag{}:public input_iterator_tag{};
struct bidirectional_tag:public forward_iterator_tag{};
struct random_access_iterator_tag:public bidirectional_iterator_tag{};
这些struct之间的继承关系是有效的is-a的挂系,所有forward迭代器都是input迭代器,以此类推。
traits并不是C++关键字或者一个预先定义好的构件,它们是一种技术,也是C++程序员共同遵守的协议,这个技术的要求之一是,它对内置类型和用户自定义类型的表现必须一样好,比如下面的advance函数:
template<typename IterT,typename DistT>
void advance(IterT&iter,Dist d)
{
if(iter is a random access iterator)
{
iter+=d;
}
else
{
if(d>=0)
{while(d--)++iter;}
else
{while(d++)--iter;}
}
}
advance()如果收到的实参是一个指针(例如const char*)和一个int,上述advance仍然必须有效运作,那意味着traits技术也必须能够施行于内置类型比如指针身上。
“traits必须能够施行与内置类型”意味着“类型内的嵌套信息(nesting information)”这种东西出局了,因为我们无法将信息嵌套于原始指针中国,因此类型的traits信息必须位于类型自身之外,标准技术是将它放进一个template及其一个或者多个特化版本中,这样的templates在标准程序库中有多个,其中针对迭代器者被命名为iterator_traits:
template<typename IterT>
struct iterator_traits;//迭代器分类的相关信息
如你所限,iterator_traits是个struct,西瓜上traits纵使被实现为struct,但它们却又被成为traits classes。
iterator_traits的运作方式是,针对每一个类型IterT,在struct iterator_traits内一定声明某个typedef名为iterator_category,这个typedef用来确认IterT的迭代器分类。
为了支持内置类型指针迭代器。Iterator_traits特别针对指针类型提供一个偏特化版本,由于指针的行为和random access迭代器累死,所以iterator_traits为指针指定的迭代器类型是:
template<typename IterT>
struct iterator_traits<IterT*>
{
typedef random_access_iterator_tag iterator_category;
};
现在我们可以对advance实践之前的伪代码。
template<typename IterT,typename DistT>
void advance(IterT&iter,DIstT d){
if(typeid(typename std::iterator_traits<IterT>::iterator_category)==typeif(std::random_access_iterator_tag))
......;//do something
}
但是这种方法将会导致编译问题,IterT的类型在编译期间获得,所以iterator_traits::iterator::category也可在编译期间确定,但if语句是在运行期才会核定,为什么将可在编译期完成的事情延迟到运行期才完成呢?这不仅浪费实践,也造成可执行代码的膨胀。
我们需要一个办法在编译期期间核定类型成功,这个办法就是重载:
template<typename IterT,typename DistT>
void doadvance(IterT&iter,DIstT d,std::random_access_iterator_tag)//用于实现random access迭代器
{
iter+=d;
}
template<typename IterT,typename DistT>
void doadvance(IterT&iter,DIstT d,std::bidirectional_iterator_tag)//用于实现bidirectional迭代器
{
if(d>=0) {while(d--) ++iter;}
else{while(d++)--iter;}
}
template<typename IterT,typename DistT>
void doadvance(IterT&iter,DIstT d,std::input_iterator_tag)//用于实现input迭代器
{
if(d<0)
throw std::out_of_range("Nagetive distance");
while(d--)++iter;
}
由于forward_iterator_tag继承自input_iterator_tag,所以上述doadvance的input_iterator_tag版本也能够处理forward迭代器,这是iterator_tag structs继承关系带来的一项红利,实际上这也是public继承带来的部分好处:针对base class编写的代码用于derived class也行得通。
有了这些doadvance重载版本,advance需要做的只是调用它们并且额外传递一个对象,后者必须带有适当的迭代器分类,于是编译期运用重载解析几只调用适当的实现代码:
template<typename IterT,typename DistT>
void advance(IterT&iter,DistT d)
{
doadvance(iter,d,typename std::iterator_traits<IterT>::iterator_category());
}
《Effective C++》再次探索traits技法的更多相关文章
- C++中的Traits技法
Traits广泛应用于标准程序库.Traits classes使得"类型相关信息"在编译期可用. 认真读完下面的示例,你应该就懂了Traits技法,其实并不难. #include ...
- C++ traits技法的一点理解
为了更好的理解traits技法.我们一步一步的深入.先从实际写代码的过程中我们遇到诸如下面伪码说起. template< typename T,typename B> void (T a, ...
- 带你深入理解STL之迭代器和Traits技法
在开始讲迭代器之前,先列举几个例子,由浅入深的来理解一下为什么要设计迭代器. //对于int类的求和函数 int sum(int *a , int n) { int sum = 0 ; for (in ...
- STL源代码剖析(二) - 迭代器与traits技法
提要 先看一段用迭代器的代码: int a[] = {1, 2, 3, 4, 5}; vector<int> v1( a, a+5); vector<int>::iterato ...
- 仿SGI STL的traits技法
首先是iterator traits,这个是用来萃取迭代器的特性的 #ifndef _STL_ITERATOR_H_ #define _STL_ITERATOR_H_ #include <cst ...
- Traits技法
扮演"特性萃取机"角色,萃取各个迭代器的特性(迭代器的相应类型) 模板特例化:提供一份template定义式,而其本身仍为templatization 通过class templa ...
- STL源码--iterator和traits编程技法
第一部分 iterator学习 STL iterators定义: 提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达方式. 任何iteartor都应该提供5 ...
- [转载]《STL源码剖析》阅读笔记之 迭代器及traits编程技法
本文从三方面总结迭代器 迭代器的思想 迭代器相应型别及traits思想 __type_traits思想 一 迭代器思想 迭代器的主要思想源于迭代器模式,其定义如下:提供一种方法,使之能够依 ...
- 对C++ templates类模板的几点补充(Traits类模板特化)
前一篇文章<浅谈C++ templates 函数模板.类模板以及非类型模板参数>简单的介绍了什么是函数模板(这个最简单),类模板以及非类型模板参数.本文对类模板再做几点补充. 文章目录1. ...
- STL内存管理
1. 概述 STL Allocator是STL的内存管理器,也是最低调的部分之一,你可能使用了3年stl,但却不知其为何物. STL标准如下介绍Allocator the STL includes s ...
随机推荐
- 7.MongoDB系列之聚合框架
1. 管道阶段和可调参数 聚合框架基于管道的概念.他由多个阶段组成,每个阶段都会提供一组按钮或可调参数.每个阶段对其输入执行不同的数据处理任务,并生成文档已作为输出传递到下一阶段. 2. 阶段常见操作 ...
- 齐博X1到底是个什么鬼?
什么是齐博/齐博CMS之X1? 齐博X1是齐博软件基于thinkphp5开发的内容管理系统,拓展性非常强,后台一键升级,后台提供丰富的频道模块云市插件市场.风格市场.钩子市场,所有都是一键在线安装. ...
- 小米MIUI禁止系统更新
删除downloaded_rom的文件夹,随便找一个文件(文件,不是文件夹),重名为downloaded_rom(是把一个文件重命名),这样系统后台偷偷下载时,就不知道该存放更新包的文件,就无法偷偷更 ...
- python批量依赖包操作
1.导出所有的python依赖 pip freeze > requirements.txt #requirements.txt 为自定名称,可以指定路径 2.自动安装所有依赖包 pip in ...
- Elasticsearch rest-high-level-client 基本操作
Elasticsearch rest-high-level-client 基本操作 本篇主要讲解一下 rest-high-level-client 去操作 Elasticsearch , 虽然这个客户 ...
- RabbitMQ安装说明文档(超详细版本)
RabbitMQ安装说明文档(超详细版本) 1. 安装依赖环境 在线安装依赖环境: yum install build-essential openssl openssl-devel unixODBC ...
- 第一阶段:linux运维基础·1
1. 服务器的主要硬件是?以及其作用是? cpu 相当于人体的大脑,负责计算机的运算和控制 内存 解决cpu与硬盘之间速度不匹配的问题 磁盘 永久存放数据的存储器 主板 直接或间接的将所有的设备连接在 ...
- Java函数式编程:二、高阶函数,闭包,函数组合以及柯里化
承接上文:Java函数式编程:一.函数式接口,lambda表达式和方法引用 这次来聊聊函数式编程中其他的几个比较重要的概念和技术,从而使得我们能更深刻的掌握Java中的函数式编程. 本篇博客主要聊聊以 ...
- python uiautomator
电脑连接上一个手机或多个手机, 确保adb已经添加到环境变量中,执行下面的命令会自动安装本库所需要的设备端程序:uiautomator-server .atx-agent.openstf/minica ...
- webpack 配置echarts 按需加载
引入babel-plugin-equire插件,方便使用.yarn add babel-plugin-equire -D 在.babelrc文件中的配置 { "presets": ...