欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

stl标准库 iterator_traits

程序员文章站 2022-12-21 20:20:23
为什么标准库里要有traits? 我们先回忆一下,标准库提供的算法的一些特征: 参数一般包括iterator。 要根据iterator的种类,和iterator包装的元素的类型等信息,来决定使用最优化的算法。 比如如果是vector的iterator,那么就可以使用+, 操作; 如果是list的it ......

为什么标准库里要有traits?

我们先回忆一下,标准库提供的算法的一些特征:

  • 参数一般包括iterator。

  • 要根据iterator的种类,和iterator包装的元素的类型等信息,来决定使用最优化的算法。

    比如如果是vector的iterator,那么就可以使用+,-操作;

    如果是list的iterator,那么就不可以使用+,-操作。

所以,算法必须知道一些关于iterator的信息。

有一些容器对应的iterator是个类,所以在这个类里,定义了如下的信息:

template<typename t>
struct __list_iterator { 
  typedef bidirectional_iterator_tag     iterator_category;
  typedef t                              value_type;
  typedef t*                             pointer;
  typedef t&                             reference;
  typedef ptrdiff_t                      difference_type;

有了上面定义的定义,算法就能够知道iterator的信息了,算法就可以正常工作了。到这里位置貌似没有traits什么事,

但是,vector,array的iterator并不是类,而是c++里内置的指针,当把内置指针当参数传递给算法后,算法无法得知iterator里定义的iterator_category,value_type,difference_type等信息,算法就无法工作。怎么办?

加一个中间层,也就是创建一个iterator_traits类,它包装了iterator,并使用模板技术,来解决上面的问题。

traits是萃取机的意思,也就是萃取iterator里的信息,并给到算法。

traits技术:

//使用iterator提供的信息
template<typename iterator>
struct iterator_traits
{
  typedef typename iterator::iterator_category iterator_category;
  typedef typename iterator::value_type        value_typep;
  typedef typename iterator::difference_type   difference_type;
  typedef typename iterator::pointer           pointer;
  typedef typename iterator::reference         reference;
};

//由于无法使用iterator的信息,所以traits自己提供了。
//局部特化,c++内置指针。
template<typename t>
struct iterator_traits<t *>
{
  typedef random_access_iterator_tag iterator_category;
  typedef t                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef t*                         pointer;
  typedef t&                         reference;
};

//由于无法使用iterator的信息,所以traits自己提供了。
//局部特化,c++内置指针。
template<typename t>
struct iterator_traits<const t *>
{
  typedef random_access_iterator_tag iterator_category;
  typedef t                          value_type;//注意这里不是const t;如果是const t,算法拿到这个类型,用这个类型定义变量后,却无法改变其值,那就没有作用了,所以是t。
  typedef ptrdiff_t                  difference_type;
  typedef const t*                   pointer;
  typedef const t&                   reference;
};

算法向iterator_traits类要它需要的信息,iterator_traits再向iterator要,如果要到了,就使用;如果没有要到就使用iterator_traits提供的。

算法举例:list类的size方法。

size_type size() const {
  size_type result = 0;
  distance(begin(), end(), result);
  return result;
  //return distance(begin(), end());    
}

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 {};

template <class inputiterator, class distance>
inline void __distance(inputiterator first, inputiterator last, distance& n, 
                       input_iterator_tag)
{
  while (first != last) { ++first; ++n; }
}

template <class randomaccessiterator, class distance>
inline void __distance(randomaccessiterator first, randomaccessiterator last, 
                       distance& n, random_access_iterator_tag)
{
  n += last - first;
}

template <class iterator>
inline typename iterator_traits<iterator>::iterator_category
iterator_category(const iterator&) {
  typedef typename iterator_traits<iterator>::iterator_category category;//--①
  return category();
}

template <class inputiterator, class distance>
inline void distance(inputiterator first, inputiterator last, distance& n)
{
  __distance(first, last, n, iterator_category(first));
}

代码解说:在①处,算法向iterator_traits要iterator_category的信息,如果iterator能提供,就使用iterator里的iterator_category,如果iterator不能提供,就使用iterator_traits里的iterator_category。得到iterator_category后,就可以在编译阶段确定调用哪一个__distance方法了。

注意:是在编译阶段就可以确定,比在运行阶段确定调用哪个__distance方法的效率要高。

下面代码是没有trais技术,是在运行阶段才能确定调用哪个__distance方法。

template <class iterator>
void distance(iterator& i){
  if(is_random_access_iterator(i)){
    __distance1();
  }  
  if(is_bidirectional_iterator(i)){
    __distance2();
  }
}

标准库的iterator_traits类,定义在stl_iterator.h文件里。