C++之使用traits classes表现类型信息(47)---《Effective C++》
来源:互联网 发布:apm飞控软件 编辑:程序博客网 时间:2024/05/18 01:35
条款47:请使用traits classes表现类型信息
我们声明一个advance函数,进行了iter+=d的动作:
template <typename IterT,typename DistT>void advance(IterT& iter,DistT d);
但是我们完全可以不用这样做,因为STL中支持random access,使用advance进行实现的话则需要反复进行++或者–运算,需要进行d次,非常冗杂。
STL中共有5中迭代器:
1)Input迭代器每次只能向前移动,一次一步,客户只能读取它们所指的东西,而不能进行修改,而且只能读取一次,istream_iterator是这种迭代器的代表,只适合“一次性操作算法”;
2)Output迭代器类似,一切只为输出,只能向前移动,一次一步,客户只能修改它们所指的东西,而且只能涂改一次,ostream_iterator是这种迭代器的代表,只适合“一次性操作算法”;
3)forward迭代器,这种迭代器可以做上述两种迭代器所能做的每一个,同时可以读或者写其所指物一次以上;
4)Bidirectional迭代器比上一个分类威力更大:它除了可以前向移动,还能后向移动,即双向移动;
5)random access迭代器威力更大,不仅可以进行双向移动移动,同时还可以进行移动随机步,即它可以在常量时间内向前或者向后跳转任意距离。
上述五种类型的关系可以表述为:
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{};
上述structs之间的继承关系是有效的“is-a”关系,以此类推,我们很快就能看到这个继承关系的效力。
针对advance的实现,我们真正想要使用的方式是如下这种:
template <typename IterT,typename DistT>void advance(IterT& iterT,DistT d){ if(iter is a random access iterator){ iter+=d; } else{ if(d>=0) {while(d--) ++iter;} else {while(d++) --iter;} }}
Traits这种技术对内置类型和用户自定义类型的表现一样好,如果上述advance函数收到的实参是一个指针和一个int类型,上述的advance函数仍然需要有效运作,这就要求traits技术必须也可以施行于内置类型如指针身上。类型的trait信息必须位于类型自身之外,标准技术是将其放进一个template机器一或者多个特化版本中。这样的template在标准程序库中有若干个,其中针对迭代器者被命名为iterator_traits:
方法1:
template <typename IterT>struct iterator_traits;
iterator_traits的运作方式是针对每一个类型IterT,在struct iterator_traits<IterT>内部一定声明一个typedef名为iterator_category,这个category用来确认IterT的迭代器分类。
template <...>class deque{public: class Iterator{ public: typedef random_access_iterator_tag iterator_category; ... };};template <...>class list{public: class Iterator{ public: typedef bidirectional_iterator_tag iterator_category; ... }; ...}; //用来对付用户自定义类型template <typename IterT>struct iterator_traits{ typedef typename IterT::iterator_category iterator_category; ...}; //用来专门对付指针类型template <typename IterT>struct iterator_traits<IterT*>{ typedef random_access_iterator_tag iterator_category; ...};template <typename IterT,typename DistT>void advance(IterT& iter,Dist d){ if(typeid(typename std::iterator_traits<IterT>::iterator_category)==typeid(std::random_access_iterator_tag)) ...}
现在,我们知道如何设计并实现一个traits class了:
1)确认若干你希望将来可取得的类型相关信息,例如针对迭代器而言,我们希望将来可以获得其分类;
2)为该信息选择一个名称;
3)提供一个template和一组特化版本,内含你希望支持的类型相关信息。
然而这种方式也会导致一些问题,首先会导致编译问题,IterT类型在编译期间即可确定,所以iterator_traits<IterT>::iterator_category也可在编译期间确定,但if…else…直到运行期间才可以确定,这样不仅浪费时间,而且造成可执行文件膨胀。
我们真正想要的条件式判断“编译期核定成功”之类型,恰巧C++中便有这种行为的方法,就是通过“重载”方式。
方法2:
template <typename IterT,typename DistT>void doAdvance(IterT& iter,DistT d,std::random_access_iterator_tag){ iter+=d;}template <typename IterT,typename DistT>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>void doAdvance(IterT& iter,DistT d,std::input_iterator_tag){ if(d<0){ throw std::out_of_range("Negative distance"); } while(d--) ++iter;}template <typename IterT,typename DistT>void advance(IterT& iter,DistT d){ //调用doAdvance版本必须是对iter之迭代器分类而言,必须是适当的。 doAdvance(iter,d,typename std::iterator_traits<IterT>::iterator_category());}
下面对trait class如何使用进行一个总结!
1)建立一组重载函数或者函数模板,彼此间的差异只在于各自的traits参数。令每个函数实现码与其接受之traits信息相应和。
2)建立一个控制函数或者函数模板,调用1)中创建的重载函数并传递traits class所提供的信息。
总结:
1)Traits classes使得“类型相关信息”在编译期可用。它们以templates和“templates特化”完成实现。
2)整合重载技术,traits class有可能在编译期对类型执行if…else…测试。
- C++之使用traits classes表现类型信息(47)---《Effective C++》
- 《Effective C++》读书笔记之item47:请使用traits classes表现类型信息
- Effective C++ 条款 47:使用traits classes表现类型信息
- Effective C++ Item 47 请使用 traits classes 表现类型信息
- [翻译] Effective C++, 3rd Edition, Item 47: 为类型信息使用 traits classes(特征类)(上)
- [翻译] Effective C++, 3rd Edition, Item 47: 为类型信息使用 traits classes(特征类)(下)
- 条款47:请使用traits classes表现类型信息(1)
- 条款47:请使用traits classes表现类型信息(2)
- 条款47:请使用traits classes表现类型信息
- 条款47:请使用traits classes 表现类型信息
- 条款48:请使用traints classes表现类型信息
- 《Effective C++》再次探索traits技法
- Item 47:使用Traits类提供类型信息
- 使用枚举类型 <<Effective Objective-C>>
- [c++]traits
- effective c++(04)之对象使用前初始化
- 《Effective C++》读书笔记之const高效使用
- More Effective C++:类型转换
- redis的使用(转载自:http://www.cnblogs.com/edisonfeng/p/3571870.html)
- ROS实时采集Android的图像和IMU数据
- HMM学习最佳范例
- 自定义控件之绘图篇:概述及基本几何图形绘制
- 使用Map集合写电话本程序
- C++之使用traits classes表现类型信息(47)---《Effective C++》
- linux虚拟地址空间
- python装饰器
- DateUtil工具类
- python os.mkdir创建目录失败
- springmvc文件上传
- 【总结】常见编程题型总结2-解题
- hex 排序
- mapreduce运行过程反复卡在[org.apache.hadoop.mapred.LocalJobRunner]