【STL源码剖析】第三章 迭代器(iterators)概念与traits编程技法

第三章 迭代器(iterators)概念与traits编程技法

迭代器设计思维——STL关键所在

STL的中心思想在于:将数据容器(containters)和算法(algorithms)分开,彼此独立设计,最后再以一帖胶着剂撮合在一起。

迭代器是一种smart pointer

迭代器是一种行为类似指针的对象,而指针的各种行为中最常见也最方便的便是内容提领(dereference)和成员访问(member access),因此,迭代器最重要的编程工作就是对operator* 和operator-> 进行重载工作。

Traits编程技法——STL源代码门钥

traits,又被叫做特性萃取技术,说得简单点就是提取“被传进的对象”对应的返回类型,让同一个接口实现对应的功能。因为STL的算法和容器是分离的,两者通过迭代器链接。算法的实现并不知道自己被传进来什么。萃取器相当于在接口和实现之间加一层封装,来隐藏一些细节并协助调用合适的方法,这需要一些技巧(例如,偏特化)。

首先,在算法中运用迭代器时,很可能会用到其相应型别(迭代器所指之物的型别)。假设算法中有必要声明一个变量,以“迭代器所指对象的型别”为型别,该怎么办呢?

解决方法是:利用function template的参数推导机制。

  
  template <class I, class T>
  void func_impl(I iter, T t) {
          T tmp; // 这里就是迭代器所指物的类型新建的对象
          // ... 功能实现
  }
  
  template <class I>
  inline
  void func(I iter) {
          func_impl(iter, *iter); // 传入iter和iter所指的值,class自动推导
  }
  
  int main() {
      int i;
      func(&i);
  }

我们以func()对外接口,却把实际操作全部置于func_imp1()之中。由于func_imp1()是一个function template,一旦被调用,编译器会自动进行template参数推到。于是导出型别T,顺利解决问题。

迭代器相应型别不只是“迭代器所指对象的型别”一种而已。根据经验,最常用的相应型别有五种,然而并非任何情况下任何一种都可以利用上述的template参数推导机制来取得。

函数的“template参数推导机制”推导的只是参数,无法推导函数的返回值类型。万一需要推导函数的传回值,就无能为力了。

声明内嵌型别似乎是个好主意,这样我们就可以直接获取。

  template <class T>
  struct MyIter {
      typedef T value_type; // 内嵌型别声明
      // ...
  };
  
  template <class I>
  typename I::value_type //这一行是func的回返值型别
  func(I ite) {
      return *ite;
  }
  
  // ...
  MyIter<int> ite(new int(8));
  cout << func(ite);

并不是所有迭代器都是class type,原生指针就不是。如果不是class type,就无法定义它内嵌型别。但STL绝对必须接受原生指针作为一种迭代器。template partial specialization 可以做到。

Partial Specialization (偏特化)意义:如果class template拥有一个以上的template参数,我们可以针对其中某个(或数个,但非全部)template参数进行特化工作。换句话说,我们可以在泛化设计中提供一个特化版本(也就是将泛化版本中的某些template参数赋予明确的指定)。

《泛型思维》对Partial Specialization 定义:针对(任何)template参数更进一步的条件限制所设计出来的一个特化版本。由此,面对以下这么一个class template:

  
  template<typename T>
  class C {……};  //这个泛化版本允许(接受)T为任何型别
  
  //我们更容易接受它有一个形如下的Partial Specialization 
  template<typename T>
  class C<T*> {……};  //这个泛化版本仅适用于"T为原生指针"的情况,便是"T为任何型别"的一个更进一步的条件限制

关键地带!下面这个class template专门用来萃取迭代器的特性,而value type正是迭代器的特性之一:

  template <class I>
  struct iterator_traits {
      typedef typename I::value_type value_type;
  };
  
  template <class I>
  struct iterator_traits<T*> {
      typedef T value_type;
  };
  
  template <class I> typename iterator_traits<I>::value_type
  func(I ite) {
      return *ite;
  }

func在调用 I 的时候,首先把 I 传到萃取器中,然后萃取器就匹配最适合的 value_type。(萃取器会先匹配最特别的版本)这样当你传进一个原生指针的时候,首先匹配的是带<T*>的偏特化版本,这样 value_type 就是 T,而不是没有事先声明的 I::value_type。这样返回值就可以使用 typename iterator_traits<I>::value_type 来知道返回类型。


感觉乱七八糟的,对这章的理解还不是很到位,继续往后看了。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值