《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 ...
随机推荐
- Java 集合简介 一
什么是集合? 集合就是由若干个确定的元素所构成的整体.例如,5只小兔构成的集合: 在数学中,我们经常遇到集合的概念.例如: ● 有限集合 ○ 一个班所有的同学构成的集合: ○ 一个网站所有的商品构成的 ...
- 【算法训练营day7】LeetCode454. 四数相加II LeetCode383. 赎金信 LeetCode15. 三数之和 LeetCode18. 四数之和
[算法训练营day7]LeetCode454. 四数相加II LeetCode383. 赎金信 LeetCode15. 三数之和 LeetCode18. 四数之和 LeetCode454. 四数相加I ...
- NVIDIA Isaac Gym安装与使用
NVIDIA做的Isaac Gym,个人理解就是一个类似于openai的Gym,不过把环境的模拟这个部分扔到了GPU上进行,这样可以提升RL训练的速度. 官网:https://developer.nv ...
- 前端框架Vue------>第二天学习(1)插槽
欢迎加入刚建立的社区:http://t.csdn.cn/Q52km 加入社区的好处: 1.专栏更加明确.便于学习 2.覆盖的知识点更多.便于发散学习 3.大家共同学习进步 3.不定时的发现金红包(不多 ...
- 一、docker的介绍
一.虚拟化和容器 虚拟化介绍 操作系统层虚拟化是指通过划分一个宿主操作系统的特定部分,产生一个个隔离的操作执行环境.操作系统层的虚拟化是操作系统内核直接提供的虚拟化,虚拟出的操作系统之间共享底层宿主操 ...
- 京东云开发者|ElasticSearch降本增效常见的方法
Elasticsearch在db_ranking 的排名又(双叒叕)上升了一位,如图1-1所示;由此可见es在存储领域已经蔚然成风且占有非常重要的地位. 随着Elasticsearch越来越受欢迎,企 ...
- QQ登录
public function login(){ $urlencode = urlencode("http://www.zhangxuhui.com/index/Index/callback ...
- Go语言核心36讲50
作为拾遗的部分,今天我们来讲讲与Go程序性能分析有关的基础知识. Go语言为程序开发者们提供了丰富的性能分析API,和非常好用的标准工具.这些API主要存在于: runtime/pprof: net/ ...
- C温故补缺(二):volatile
volatile 参考:CSDN volatile也是一个类型修饰符,被其修饰的变量意味着可以被某些编译器未知的因素修改,如操作系统,硬件,线程等. 当遇到volatile修饰的变量时,编译器对访问该 ...
- MySQL数据库:6、约束的概述及语法
Python基础之MySQL数据库 目录 Python基础之MySQL数据库 一.约束概述 1.为什么要约束 2.什么是约束 3.约束的分类 4.查看当前表已有的约束 二.约束语法及用法 1.无符号 ...