stl源码剖析02——iterator源码剖析与Traits编程技术/偏特化

一、迭代器相应类型

  • 前文介绍了迭代器的雏形,在使用迭代器的时候,我们可能需要知道这个迭代器所指之物的数据类型,但是C++不支持typeof()这种机制,因此我们需要一种技术来获取迭代器所指之物的类型

参数推导机制

  • 参数推导机制可以让我们推断出参数的数据类型
template<class I,class T> //此例中,T为int

void func_impl(I iter, T t)

{

    T tmp;

    //...

}


template<class I>

inline void func(I iter)

{

    func_impl(iter, *iter);

}


int main()

{

    int i;

    func(&i);

}

  • 迭代器相应类型不只是“迭代器所指对象的类型”一种而已。最常见的相应类型有5种,在后面介绍

二、声明内嵌类型

  • 上面介绍了函数的参数推导机制,推导机制虽然好,但是只能获取参数的类型,不能获取函数返回值的类型
  • 作为解决办法,声明内嵌类型是一个好主意,例如:

声明内嵌类型

  • 下面我们在MyIter中使用typedef声明一个别名,这个别名就是传入迭代器的类型的别名
  • 在func函数中,我们返回迭代器中的元素,因此我们需要知道迭代器所指之物的类型才能为其声明返回值类型,此处我们使用了typename来引出迭代器中的类型别名
//迭代器类

template<class T>

struct MyIter {

    typedef T value_type; //内嵌类型别名,用value_type来表示迭代器类所指之物的类型

    T* ptr;

    MyIter(T* p = 0) :ptr(p) {}

    T& operator*()const { return *ptr; }

};


/*

为什么要使用typename:因为编译器不知道T是什么,也就是说编译器不知道MyIter<T>::value_type

是一个类型还是一个成员函数还是一个成员变量,此处我们使用typename告诉编译器这是一种类型,

这样才能顺利编译通过

*/

template<class I>

typename I::value_type func(I ite){  //typename I::value_type 为func的返回值类型

    return *ite;

} 


MyIter<int> ite(new int(8));

cout << func(ite);

三、偏特化

  • 上面的声明内嵌类型很好用,但是并不是所有迭代器的都是class,例如原生指针就不是class(例如int*,stirng*),那么此时我们就无法使用内嵌类型了,但是STL算法、容器等都是接受原生指针作为一种迭代器的。那么针对于原生指针我们该如何处理呢?
  • 是的,偏特化(Paritial Specialization)可以做到

偏特化

  • 偏特化的概念是:我们可以针对类模板中的template参数进行特化工作。为其提供一个特化版本(也就是讲template中参数赋予明确的指定)
  • 例如下面是常规的类模板,允许接收T为任何类型
template<typename T>

class C{};
  • 下面是一个特化版本,允许接收T为原生指针的情况 
template<typename T>

class C<T*>{};

 

为迭代器声明一个偏特化

  • 在“二”中我们的迭代器没有偏特化版本,因此传入原生指针之后就不可以推导出迭代器所指之物的类型了
  • 有了偏特化,我们就可以对迭代器进行偏特化,设计出下面的迭代器
//偏特化迭代器类

template<class T>

struct MyIter<T*> {

    typedef T value_type; //这个迭代器接受原生指针,从而获得指针所指之物的数据类型

    T* ptr;

    MyIter(T* p = 0) :ptr(p) {}

    T& operator*()const { return *ptr; }

};

 

四、Traits编程技术

  • 通过上面的介绍,我们正式开始介绍Traits编程技术
  • 下面的类模板专门用来“萃取”迭代器的类型,value_type就是迭代器的特性之一:
//如果I为迭代器类,并且迭代器类中声明有类型别名,那么我们就可以萃取出其中的数据类型

template<class I>

struct iterator_traits {

    typedef typename I::value_type value_type;

};
  • traits是指:如果I定义有自己的value type,那么我们就可以通过上面设计的iterator_traits类来萃取出I的value_type(数据类型)。我们上面的func函数还可以更改为:
//萃取的使用场景

template<class I>

typename iterator_traits<I>::value_type func(I ite) {  //typename iterator_traits<I>::value_type 为func的返回值类型

    return *ite;

}
  • traits也可以有特化版本:例如下面只针对于迭代器是原生指针的偏特化版本,其能萃取出指针所指之物的数据类型
template<class T>

struct iterator_traits<T*> {

    typedef T value_type;

};

注意“指向常数对象的指针”特化本

  • 针对“指向常数对象的指针”,下面的式子会得出什么结果呢?
iterator_traits<const int*>::value_type;
  • 我们希望这种traits机制来获取迭代器的类型,但是如果上面的式子萃取出的是const int类型,那么声明就无法赋值了,因此如果迭代器是个pointer-to-const,我们应该设置下面的特化版本
template<class T>

struct iterator_traits<const T*> {

    typedef T value_type; //萃取出的是T,而不是const T

};

 

  • 下图说明了traits所扮演的“特性萃取机”角色,萃取各个迭代器的特性
  • 当然如果希望“特性萃取机”traits能够正常工作,前提是迭代器必须在自己的类中声明类型别名(typedef)

五、iterator_traits萃取机

  • 下面是迭代器源码中的iterator_traits类(其中的一个版本),其用来萃取迭代器中的相应类型
//迭代器的源码

template<class Category,class T,class Distance=ptrdiff_t,

class Pointer=T*,class Reference=T&>

struct iterator {

    typedef Category iterator_category;

    typedef T value_type; //迭代器所指之物的数据类型(其余的见下面介绍)

    typedef Distance difference_type;

    typedef Pointer pointer;
    
    typedef Reference reference;

};



//traits萃取机,其中I为迭代器类

template<class I>

struct iterator_traits {

    typedef typename I::iterator_category iterator_category;

    typedef typename I::value_type value_type;

    typedef typename I::difference_type difference_type;

    typedef typename I::pointer pointer;

    typedef typename I::reference reference;

};
  • 当然,iteraotr_traits类还必须设计针对于迭代器是pointer以及pointer-to-const的特化版本(见后面一篇文章得迭代器介绍源码)
  • 常用的迭代器相应类型有5中:value type、difference type、pointer、reference、iterator catagory

六、iterator源代码实例

  • 下面列出了SGI STL<stl_iterator.h>头文件的代码
  • 关于iostream iterators、inserter iterators、reverse iterators的实现,在后面配接器中介绍

迭代器类型

//用于标记迭代器的类型

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

 

iterator

  • 为了防止代码出错,自己定义的迭代器最好都继承这个类
template<class Category,class T,

class Distance=ptrdiff_t,class Pointer=T*,class Reference=T&>

struct iterator {

    typedef Category iterator_category;

    typedef T value_type;

    typedef Distance difference_type;

    typedef Pointer pointer;

    typedef Reference reference;

};

 

traits萃取机

//萃取机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 Iterator>

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;

};


//针对于pointer-to-const的偏特化版本

template<class Iterator>

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;

};
  • 下面这个函数可以方便的萃取出某个迭代器的类型(category)
//参数为迭代器

template<class Iterator>

inline typename iterator_traits<Iterator>::iterator_category

iterator_category(const Iterator&)

{

    typedef typename iterator_traits<Iterator>::iterator_category category;

    return category();

}
  •  下面这个函数可以方便的萃取出某个迭代器的distance type
//参数为迭代器

template<class Iterator>

inline typename iterator_traits<Iterator>::difference_type*

distance_type(const Iterator&)

{

    return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);

}
  • 下面这个函数可以方便的萃取出某个迭代器的value type
//参数为迭代器

template<class Iterator>

inline typename iterator_traits<Iterator>::value_type*

distance_type(const Iterator&)

{

    return static_cast<typename iterator_traits<Iterator>::value_type*>(0);

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值