EC读书笔记系列之18:条款47、48
条款47 请使用traits classes表现类型信息
记住:
★Traits classes使得“类型相关信息”在编译期可用。它们以templates和“templates特化”完成实现
★整合重载技术后,traits classes有可能在编译期对类型执行if...else测试
---------------------------------------------------------
STL共有5种迭代器:
①Input迭代器: 如:istream_iterator
仅前移,一次一步;
客户只可读取,且只能读取一次;
②Output迭代器:如ostream_iterator
仅前移,一次一步;
客户只可涂写其所指物,且只能涂写一次,不能读取
③Forward迭代器:
只能使用++操作符来单向遍历容器(不能用--);
可读写;
④Bidirectional迭代器:如STL的list、set、map的迭代器
可以用++和--操作符来双向遍历容器;
可读写;
⑤Random access迭代器: 如vector、deque和string的迭代器
可执行“迭代器算术”;
可直接访问容器中的任意一个元素的双向迭代器;
对于这五种分类,C++标准库提供专门的类型标记结构对它们进行区分:
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{};
------------------------------
Traits并非C++关键字或一个预先定义好的构件;它是一种技术,也是一个C++程序员共同遵守的协议。
------------------------------
设计并实现一个traits class
使用traits技术可以在编译期间获取某些类型信息,它要求对内置类型和用户自定义类型表现得一样好。标准模板库是把traits信息放到模板中,其中针对迭代器的被命名为iterator_traits,它是一个结构体:
template<typename IterT>
struct iterator_traits;
其工作原理是:针对每一个类型IterT,在结构体中声明某个typedef名为iterator_category,这个typedef用于确认IterT的迭代器分类。它包括两部分实现:
(1)对于自定义类型,用户必须在类模板中声明一个typedef名为iterator_category,比如对双端队列deque和列表list的模板类:
template<typename ...> class deque{ public: class iterator{ public: typedef random_access_iterator_tag iterator_category; ...};... }; template<typename ...> class list{ public: class iterator{ public: typedef bidirectional_access_iterator_tag iterator_category; ...};... };
在iterator_traits中,获取迭代器的类型信息:
template<typename IterT> struct iterator_traits{ typedef typename IterT::iterator_category iterator_category; ... };
(2)对于内置类型的指针,iterator_traits提供一个偏特化版本:
template<typename IterT> //template偏特化 struct iterator_traits<IterT*>{ //针对内置指针 typedef random_access_iterator_tag iterator_category; ... };
因此,设计并实现traits class的步骤是:
(1)确认若干希望将来可取得的类型相关信息(例如对于迭代器,希望获取它的分类)。
(2)为该信息选择一个名称(例如iterator_category)。
(3)提供一个模板和一组特化版本(如iterator_traits),内含希望支持的类型相关信息。
-------------------------------------
traits class的使用
如上所述的类型信息可在编译期间获取,但是此时需要对传递来的指针类型做出判断,如果使用if...else...分支判断语句,只有在运行期间才能获取。怎么办?
可以使用函数重载的办法:重载函数需要在编译期间通过确定参数类型来决定调用哪个版本,正好可以解决“编译期条件句”的问题。
PS:这个想法实在太牛了!
如前所述的迭代器类型问题,可以设计多个重载函数做适配于各个类型的操作,然后在同一个函数中调用它们。
template<typename IterT, typename DistT> void advance( IterT& iter, DistT d ) { doAdvance( //doAdvance()有多个重载,其版本不同之处在于传递的迭代器的参数不同 iter, d, typename std::iterator_traits<IterT>::iterator_category() ); .. }; template<typename IterT, typename DistT> //这份实现用于random access迭代器 void doAdvance( IterT& iter, DistT d, std::random_access_iterator_tag ) { iter+=d; } template<typename IterT, typename DistT> //这份实现用于bidirectional迭代器 void doAdvance(IterT& iter, DistT d, std::bidirectional_iterator_tag) { if(d>=0){ while(d--) ++iter; } else{ while(d++) --iter; } } template<typename IterT, typename DistT> //这份实现用于input迭代器,由于forward迭代器派生于input迭代器,也可用于forward迭代器 void doAdvance(IterT& iter, DistT d, std::input_iterator_tag) { if(d<0){ throw std::out_out_range("Negnative distance"); //对于input或forward迭代器,移动负距离会导致不明确的行为,因而抛出异常 } while(d--) ++iter; }
可见,使用traits class的方法是:
(1)建立一组重载函数或函数模板,彼此间差异只在于各自的traits参数,令每个函数实现代码与其接受的traits信息相适配。
(2)建立一个控制函数或函数模板,它调用上述重载函数并传递traits class所提供的信息。
条款48 认识template元编程(TMP)
记住:
★TMP(模板元编程)可将工作由运行期移往编译期,因而得以实现早期错误侦测和更高的执行效率
★TMP可被用来生成“基于政策选择组合”的客户定制代码,也可用来避免生成对某些特殊类型并不适合的代码
--------------------------------------------------------------------------------------------------
TMP可以将部分执行期的任务提前至编译期完成,从而可以更早发现错误,更高效(编译时间会变长,但是执行期效率会高)。且TMP对“难以或甚至不可能于运行期实现出来的行为”的表现也很吸引人!
----------------------------------------------
TMP是图灵完备的,可以执行分支语句和循环(通过递归实现)。如解决阶乘问题:
template<unsigned n> //一般情况,递推关系式 struct Factorial{enum { value = n * Factorial<n-1>::value }; }; template<> //特殊情况,以结束递归 struct Factorial<0>{enum{value = 1}; };int main() {std::cout<<Factorial<5>::value;std::cout<<Factorial<10>::value; }
-----------------------------------------------------
使用TMP一般可以有如下效果:
(1)确保量度单位正确。
(2)优化矩阵运算。
(3)生成客户定制的设计模式。
转载于:https://www.cnblogs.com/hansonwang99/p/5025290.html
EC读书笔记系列之18:条款47、48相关推荐
- 密码学读书笔记系列(三):《商用密码应用与安全性评估》
密码学读书笔记系列(三):<商用密码应用与安全性评估> 思考/前言 第1章 密码基础知识 1.1 密码应用概述 1.2 密码应用安全性评估(密评)的基本原理 1.3 密码技术发展 1.4 ...
- 《浪潮之巅》读书笔记系列:IBM 蓝色巨人
<浪潮之巅>读书笔记系列:IBM 蓝色巨人 精彩部分 1. IBM公司可能是的世界上为数不多的成功逃过历次经济危机,并且在历次技术革命中成功转型的公司. 2. 一个公司创始者的 ...
- Missing separate debuginfos, use: debuginfo-install 解决方法如下----笛风读书笔记系列
读书笔记系列之:Missing separate debuginfos, use: debuginfo-install 解决方法如下 ...
- 《ASP.NET Core In Action》读书笔记系列五 ASP.NET Core 解决方案结构解析1
<ASP.NET Core In Action>读书笔记系列五 ASP.NET Core 解决方案结构解析1 参考文章: (1)<ASP.NET Core In Action> ...
- C#刨根究底:《你必须知道的.NET》读书笔记系列
一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP-王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...
- 密码学读书笔记系列(一):《密码故事——人类智力的另类较量》
密码学读书笔记系列(一):<密码故事--人类智力的另类较量> 第一章 玛丽女王的密码 第二章 不可破译的密码 第三章 加密的机械化 第四章 破解恩格玛 第五章 语言上的隔阂 第六章 艾丽丝 ...
- 读书笔记系列1——MySQL必知必会
读书笔记系列1--MySQL必知必会 文章目录 读书笔记系列1--MySQL必知必会 MySQL官方文档:https://dev.mysql.com/doc/ 第一章 数据库基础 *2021.11.2 ...
- Web高级征程:《大型网站技术架构》读书笔记系列
来源:http://www.cnblogs.com/edisonchou/p/3773828.html 一.此书到底何方神圣? <大型网站技术架构:核心原理与案例分析>通过梳理大型网站技术 ...
- 12篇读书笔记系列-1、置身事内
导语:当今社会短视频横行,导致全民专注力下降:年关将近,我回顾近几年看过的书籍,竟没有一本能简要复述,不能回想起获取了作者的哪些观点,更别提对作者观点的升华:所以,接下来的12本书,我强迫自己静下心来 ...
- 读书笔记系列--《理解专业程序员》tips
理解专业程序员,给您带来大师的tips *"什么东西是绿的,有轮子,而且长在房子的周围"?* *"猜不出来,答案呢"?* *"是草,轮子是我瞎说的&q ...
最新文章
- 高并发系统搭建:web负载均衡
- php 获得用户地址吗,php获得用户的真实IP地址_PHP教程
- ubuntu18.04安装pycharm专业版
- mysql中怎么查询单行单列_MySql中的子查询-结果单行单列
- 速神经网络的训练算法LARS/LAMB工作原理 --UC Berkeley在读博士生尤洋
- shell-1.shell注释
- SQL嵌套语句执行顺序
- cv mat的shape_将ndarray转换为cv::Mat的最简单方法是什么?
- Twitter开放平台api key申请流程 (Twitter Consumer Key)
- 英文材质翻译表_英语翻译5大技巧,用了才知道是真好
- SQLAlchemy schema.Column
- 一体机硬盘被格式化了的资料恢复法子
- Python3 从零单排17_类的继承
- java.text.MessageFormat 专题
- java递归生成无限层级的树--分类管理
- 获取计算机关机时间,查询电脑开关机时间的vbs代码
- 【硬件】详解电流采样电路
- 《网页配色密码》 一本易读实用的好书
- 从写作到演讲,虾米君不断尝试的 2021|年终回顾
- 07 Anykey图像优化及文字头像生成与加载