STL中的特性萃取机iterator_traits

2013年4月26日 由 Creater 留言 »

很早以前,第一次看STL源码,第一次接触iterator_traits,我觉得他是一个巧妙的发明。
而现在再来看他,我觉得他变得更加绝妙。

iterator_traits是和迭代器在一起的,是针对迭代器来说的。也就是说通过iterator_traits可以了解到迭代器的信息和迭代器所指向元素的信息。
在编码的时候,往往需要定义一个迭代器指向对象类型的变量或者对象,我们可以利用函数模板推导来获得value_type类型。

template <class I, clss T>
void _func(I iter, T t)
{
	T tmp;
	/*---*/
}

template <class I>
void func(I iter)
{
	_func(iter, *iter);
}


func是我们知道的接口,传入一个迭代器作为参数,但是我们函数内部需要定义一个该迭代器指向类型的对象,就可以像上面那样包裹并利用模板推导来完成。
但是如果我们想根据模板参数I,和I指向的类型value_tyoe作为返回值,上边好像就无能为力了。

现在该特性萃取机iterator_traits上场了

template <class Iterator>
struct iterator_traits {
  typedef typename Iterator::iterator_category iterator_category;
  typedef typename Iterator::value_type        value_type;
  typedef typename Iterator::difference_type   difference_type;
  typedef typename Iterator::pointer           pointer;
  typedef typename Iterator::reference         reference;
};

template <class 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;
};

template <class T>
struct iterator_traits<const T*> {
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef const T*                   pointer;
  typedef const T&                   reference;
};

先大体看看,就知道了任何迭代器都需要有以上的哪几种类型定义
iterator_category;
value_type;
difference_type;
pointer;
reference;
通过萃取器就可以采用如下方式获取迭代器指向元素的value_type
iterator_traits::value_type
但是内置类型的指针不是类结构,不能定义value_type,但是我们可以通过模板特化解决。
那么为什么还要针对const T*特化呢?因为不特化的话,value_type将是const T。

另外iterator_category的作用是,针对不同的迭代器类型在加上一个数时效率不同,而需要分开处理来设计的。比如advance

template <class InputIterator, class Distance>
inline void __advance(InputIterator& i, Distance n, input_iterator_tag) {
  while (n--) ++i;
}

#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma set woff 1183
#endif

template <class BidirectionalIterator, class Distance>
inline void __advance(BidirectionalIterator& i, Distance n, 
                      bidirectional_iterator_tag) {
  if (n >= 0)
    while (n--) ++i;
  else
    while (n++) --i;
}

#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma reset woff 1183
#endif

template <class RandomAccessIterator, class Distance>
inline void __advance(RandomAccessIterator& i, Distance n, 
                      random_access_iterator_tag) {
  i += n;
}

template <class InputIterator, class Distance>
inline void advance(InputIterator& i, Distance n) {
  __advance(i, n, iterator_category(i));
}

advance为对外开放的接口,客户只知道该接口可以对一个指针进行增加,并不知道针对不同的迭代器处理方式不一样,比如随机迭代器只需要一次加运算就可以完成。
在advance里调用了__advance(i, n, iterator_category(i));或者__advance(i, n, iterator_category::itreator_category());通过特性萃取器iterator_category可以提取出当前迭代器的类型来选择不同的处理方式。其中的iterator_category(i),只不过是利用了函数模板的推导性进行了包装,返回的是一个对象。

template <class Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&) {
  typedef typename iterator_traits<Iterator>::iterator_category category;
  return category();
}
广告位

发表评论

你必须 登陆 方可发表评论.