【c++从菜鸡到王者】第八篇:深度剖析Traits技法

Traits编程技法

  • Traits技法就是提取相应型别,什么是相应型别?迭代器所指对象的型别便是其中之一。(除此之外还有4中所必要的型别,后面详细介绍)
  • 在算法中我们要用到迭代器,假如一个算法需要使用迭代器中所指对象的型别来创建一个对象。就需要获取迭代器中的型别信息。我们知道每个容器都有专属的迭代器,所以每个容器的迭代器都含有我们所需要的相应的型别信息,所以需要一个特殊的装置帮我们提取相关的信息,那就是Traits(萃取机)

  • 下面我们具体介绍一下这5个型别的具体含义

    • value_type :指迭代器所指对象的型别

    • difference_type:用来表示两个迭代器之间的距离。因此它用来表示一个容器的最大容量

      typename iterator_traits<I>::difference_type;
      //任何时候我们需要迭代器I的difference_type 都可以这样写
      
    • reference_type、pointer_type :在c++函数中如果要传回左值(允许改变所指对象的内容),都是以by reference 的方式进行;就pointer_type而言,我们能够传回一个pointer,指向迭代器所指之物。

      Item& operator*()const{return *ptr;}
      Item* operator->()const{return ptr;}
      //Item&就是reference_type Iter*就是pointer_type
      
    • iterator_category:简单来说就是提取迭代器类型,为算法选择最有利于其功能的迭代器类型(迭代器类型有单向,双向,只读,只写,随机 迭代器)。

      • traits有能力提取迭代器的种类,我们利用其作为算法的一个参数,这个类别必须是class type,然后就能调用算法的不同形式,以提升效率
      //下面我将以advance()算法来描述这个类别
      //首先是5个用作标记的型别
      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();
      //下面是advance()算法的具体实现
      template<class InuputIterator,class Distance>
      inline void __advance(InputIterator& i,Distance n,input_iteratoo_tag){
          ...
      }
      template<class ForwardIterator,class Distance>
      inline void __advance( ForwardIterator& i,Distance n, forward_iterator_tag){
          ...
      }
      template<class BidirectionalIterator,class Distance>
      inline void __advance( BidirectionalIterator& i,Distance n, bidirectional_iterator_tag){
          ...
      }
      template<class RandomAccesslIterator,class Distance>
      inline void __advance( RandomAccesslIterator& i,Distance n, random_access_iterator_tag){
          ...
      }//以上函数的具体实现不同
      //每个__advance都只声明类别,不指定参数,只是纯粹用来激活重载机制的。
      

      这时我们需要准备一个上层接口,它只接受两个参数,当它把上述工作给__advance()时,才自行加上第三参数:迭代器类型。然后这个函数必须从迭代器中推导出类型。当然这个工作交traits。

      template<class InputIterator,class Distance>
      inline void advance(InputIterator &i,Distance n){
          __anvance(i,n,iterator_traits<InpurIterator>::iterator_category());
      }
      

      为了满足上述行为,traits必须还要增加一个相应的型别:iterator_category;

      template<class I>
      struct iterator_traits{
          ...
          typedef typename I::iterator_category iterator_category;
      };
      //另外还有两个偏特化版本,是针对原始指针设计而成,T*,const T*.他们的迭代器类型都是随机访问迭代器。
      
      • 注意:任何一个迭代器都应该落在"该迭代器隶属中"最强化的那一个。例如一个迭代器int*是上面的那5个迭代器类型,但是在程序中我们必须把它当作随机访问迭代器;

        STL算法的命名法则:以算法所能接受的最低阶迭代器类型,来为其迭代器类型命名。

      • 在上面我所列举的5个类型的型别定义中,后面3个为什么要公有继承前面的两个迭代器类型,为了消除“单纯传递调用的函数”,比如当客端调用distance()并使用Forward iterator时,统统都会调用Input iterator版的那个的__distance()。因为distance()算法里没有Forward iterator 版本。如果没有继承,我们就会在distance()的Forward版本里调用Input版本的。

  • iterator的保证

    • 为了规范,每个迭代器都要提供这5个类型。为了以防你初心,STL提供了一个iterator class 每个迭代器都可以继承它,以保证规范

      template<class Category,class T,class Distance=ptrdoff_t,class Pointer=T*,class Refrence=T&>
      struct iterator{
          typedef Category iterator_category;
          typedef T  value_type;
          typedef Distance difference_type;
          typedef Pointer pointer;
          typedef Reference reference;
      };
      //由于后面3个参数是默认的,所以我们在继承的时候必须指定前面的2个参数
      

总结:设计适当的型别是迭代器的责任,设计合适的迭代器是容器的责任,只有容器才知道设计出怎样的迭代器来遍历自己,并执行迭代器该执行的各种行为。至于算法完全独立于容器于迭代器,自行发展,只是设计时以迭代器为对外接口形式。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值