首页 > 学院 > 开发设计 > 正文

STL源码剖析学习笔记(三)

2019-11-08 01:34:01
字体:
来源:转载
供稿:网友

STL源码剖析学习笔记(三)

iterator和traits编程技法(下)

前面说到,利用模板的参数推导机制可以推导参数,但是如果我们需要该类型的返回值作为参数,则无法通过这个方法获取,这个时候,就需要内建类型。 什么是内建类型呢?我们还用程序来举例子:

template <typename T>class myIterator{ ...};

这样一个模板类里,我们需要获取T的类型,可以利用typedef

template <typename T>class myIterator{ typedef T value_type; ...};

这样,当我们需要T的类型作为函数的返回值的时候,可以这么写

template<typename T>typename T::value_type func(T x){};

注意这里的typename T::value_type 是函数的返回值类型,这里用typename关键字,也是因为如果不加的话,编译器不知道T::value_type是一个类型还是一个成员变量。

这样,我们就可以利用这个特性来写iterator的萃取器trait了。 看好下面这个代码

template<class I>struct iterator_traits{ typedef typename I::value_type value_type};

刚才的函数就可以写成

template<class T>typename iterator_traits<T>::value_type func(T x){};

即如果你这个模板T一旦定义了内嵌类型value_type,你就可以使用iterator_traits将其value_type萃取出来,这么多一层包裹的意义是什么呢?前面说过,原生指针类型必须是iterator,比方说int*,它并没有定义value_type,就无法做到模板的统一了,那么这里迭代器的traits就利用了模板的偏特化这样一个特性,定义了原生指针的value_type。 什么是偏特化?简单点说: template<class T,class I>是基础版本,那么 template<class T,int>就是偏特化版本,而 template<class T,class I*>也是偏特化版本, template<char, int>就是全特化版本了。 编译器对模板对号入座的时候,先考虑全特化,再考虑偏特化,最后考虑基础版本。说到这里,我们就可以让原生指针的萃取器trait变成一个偏特化的版本:

template <class T>struct iterator_traits<T*>{typedef T value_type;};template <class T>struct iterator_traits<const T*>{typedef T value_type;};

这样就解决了原生指针的问题。

迭代器通常需要定义以下几个type:

value_type;difference_type;pointer;reference;iterator_category;

第一个不用说了;第二个定义了表示两个迭代器之间“距离”这样一个东西的类型;第三个和第四个可以用以下两个式子来解释Item* Operator->() const {return ptr;} Item& operator*() const {return *ptr;} 前者返回值就是pointer,后者就是reference;第五个是指迭代器的类型,有以下几种: 1. input iterator 2. output iterator 3. forward iterator 4. bidirectional iterator 5. random access iterator

原生指针是第五个种类哦。 这里的五个级别,以最强的那个为准,当你针对迭代器写函数的时候,如果它是random access iterator,那么它一定也是1、3、4或者2、3、4,那么针对它写的偏特化版本的函数模板,就不一定适用于1、2、3、4,因为它级别最高。

下一篇将讲述一些基本的容器。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表