C++ 请使用特质类(traits classes)表现类型信息

原创 2018年04月16日 19:15:04

20180404 C++ 请使用特质类(traits classes)表现类型信息


STL主要由“用以表现容器、迭代器和算法”的templates构成,但也覆盖若干工具性模板,其中一个名为advance,用来将某个迭代器移动某个特定距离:
template<typename IterT,typename DistT>  //将迭代器向前移动d单位
void advance(IterT& iter,DistT d);    //若d<0 则向后移动。


观念上advance只是做iter+=d动作,但其实不可以全然那么实践,因为只有随机访问(random access)迭代器才支持+=操作,面对其他威力不那么强大的迭代器种类,advance必须反复执行++或--,共d次。




复习STL的迭代器分类(共5种):
(1)Input迭代器:只能向前移动,一次一步,客户只能读取(不能修改)他们所指的东西,而且只能读取一次,他们模仿指向输入文件的阅读指针(read pointer);C++程序库中的istream_iterators是这一分类的代表;
(2)Output迭代器情况类似,但一切只为输出,另外客户只能修改他们所指的东西,而且只能修改一次,他们模仿指向输出文件的修改指针(write pointer);ostream_itetators是这一分类的代表。


上述两种迭代器威力较小(只能向前移动),所以只适合“一次性操作算法(one-pass algorithms)”。




(3)forward迭代器:这种迭代器可以做前述所有的操作,而且可以读或写所指物一次以上,这使得它们可施行于多次性操作算法。
(4)Bidirectional迭代器:威力更强大,它除了可以向前移动,还可以向后移动,STL的list迭代器就属于这一类,set,multiset,map,和multimap的迭代器也都属于这一类。
(5)随机访问迭代器:威力最大,它可以执行迭代器运算,即它可以在常量时间内向前或向后跳跃任意距离。vector,deque,和strig提供的迭代器就是这一分类。




对于以上5种迭代器,C++标准程序库分别提供专属的卷标结构(tag struct)加以确认:
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关系,所有的forward迭代器都是input迭代器,依此类推。




我们希望使用如下方式实现advance:


template<typename IterT,typename DistT>
void advance(IterT& iter,DistT d)
{
  if(iter is a random access iterator)
  {
    iter += d;  //针对random access迭代器使用迭代器算数运算
  }
  else
  {
    if(D >= 0){while(d--) ++iter;}  //针对其他迭代器分类反复调用++或--
    else {while(d++) --iter;}
  }
}




这种方法首先必须判断iter是否为随机访问迭代器,traits会帮你办到。




标准技术将类型的traits信息放进一个template及其一个或多个特化版本中,这样的templates在标准程序库中有若干个,其中针对迭代器者被命名为iterator_traits:




template<typename IterT>  //模板,用来处理迭代器分类的相关信息
struct iterator_traits;


iterator_traits的运作方式是,针对每一个类型IterT,在结构体iterator_traits<IterT>里一定声明某个typedef名为iterator_category。这个typedef用来确认Itert的迭代器分类。


以下是对advance实践先前的伪码(pseudocode):
typename<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))
  ...
}




上述代码会导致编译问题。
我们真正想要的是一个条件式(即if...else语句)判断“编译期核定成功”的类型。恰巧C++有一个取得这种行为的办法,那就是重载。


为了让advance的行为如我们所愿,我们需要做的就是产生两版重载函数,内含advance的本质内容,但各自接受不同类型的iterator_category对象,我们将这两个函数取名为doAdvance:


template<typename IterT,typename DistT>//这份实现用于随机访问迭代器
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迭代器
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,d,
    typename
      std::iterator_traits<IterT>::iterator_category()
    );
}






注意:
1、特性类(Traits class)使得“类型相关信息”在编译期可用,它们以“模板”和
“模板特化”完成实现。
2、整合重载技术(overloading)后,特性类(Traits class)有可能在编译期对类型执行if...else测试。










【吴刚】字体设计与表现视频教程

字体设计是广告设计和交互设计的重点,字体设计的主要任务就是要对文字的形象进行符合设计对象特性要求的艺术处理,以增强文字的传播效果。字体设计能力是广告和设计师岗位核心能力之一,本课程旨在系统剖析字体设计构形知识和技能,并通过课程项目的训练来提高字体设计的实际技能,在实际工作中能举一反三。
  • 2018年03月18日 19:18

Effective C++ 条款 47:使用traits classes表现类型信息

(一) stl主要由“用以表现容器、迭代器和算法”的template构成,但也覆盖若干工具性的templates,其中一个名为advance,将某个迭代器移动某个给定距离: template vo...
  • u010470972
  • u010470972
  • 2014-09-25 14:36:59
  • 607

条款47:请使用traits classes表现类型信息(2)

条款47:请使用traits classes表现类型信息(2)    Use traits classes for information about types.    大家好,上一篇我们讨论了如何...
  • scofieldzhu
  • scofieldzhu
  • 2009-10-22 20:52:00
  • 729

条款47:请使用traits classes表现类型信息(1)

条款47:请使用traits classes表现类型信息(1)    Use traits classes for information about types.    今天我们讨论的这款内容涉及到...
  • scofieldzhu
  • scofieldzhu
  • 2009-10-22 16:29:00
  • 579

c++中traits class表示类型信息

c++中traits class表示类型信息 隐式接口和编译期多态 1.classes和template都支持接口(interfaces)和多态(polymorphism)。 2...
  • chenglinhust
  • chenglinhust
  • 2012-09-23 09:17:37
  • 1570

条款47:请使用traits classes 表现类型信息

/*条款47:请使用traits classes 表现类型信息*/ //Traits 是一种技术,一个C++程序员共同遵守的协议,它的要求之一是:它对内置类型和用户自定义类型的表现必须一样好 //ad...
  • sbfksmq
  • sbfksmq
  • 2015-09-28 17:57:19
  • 211

条款47:请使用traits classes表现类型信息

STL迭代器可分为五类: struct input_iterator_tag{};struct output_iterator_tag{};struct forward_iterator_tag:pu...
  • beecindy
  • beecindy
  • 2010-04-05 19:26:00
  • 305

细说 C++ Traits Classes

最近在看侯捷的《STL源码剖析》,看到第三章有关 traits 的介绍,被搞得一头雾水,看了半天不知所云。为了彻底了解这个技法的原理,硬着头皮上网查了资料,并结合 Scott Meyers 的 《Ef...
  • lihao21
  • lihao21
  • 2017-02-13 08:29:38
  • 2236

Effective C++ 条款47

本节条款的题目:请使用trait classes来表示类型信息本节条款主要讲述的技术是如何在编译期间实现对迭代器类型的判断,根据判断的类型进行最优处理。 我们先来看一下迭代器的种类: 1.inpu...
  • u011058765
  • u011058765
  • 2015-06-09 11:07:29
  • 771
收藏助手
不良信息举报
您举报文章:C++ 请使用特质类(traits classes)表现类型信息
举报原因:
原因补充:

(最多只允许输入30个字)