STL学习笔记之traits技术

来源:互联网 发布:dota2网络连接不上 编辑:程序博客网 时间:2024/05/01 02:39

Traits技术详解

 

问题1:如何根据指针或者迭代器,获得指针或者迭代器所指对象的类型??

 

例如:

template<typename Iterator>  

void func(Iterator iter)  

{  

    //函数体  

}  

如果此时,要想在函数体中声明一个变量,变量的类型为迭代器所指对象的类型。

 

解决方法:

利用模版函数的参数类型推导机制。即根据传入的参数类型来确定模版类型的类型。如上,根据传入func()函数的类型,来确定Iterator所代表的类型。

 

template<typename Iterator, typename T>  

void func_impl(Iterator iter, T t)  

{  

    T temp; //这里就解决了问题  

    //这里做原本func()的工作  

}  

  

template<typename Iterator>  

void func(Iterator iter)  

{  

    func_impl(iter, *iter); //func的工作全部都移到func_impl里面了  

 

函数func作为对外接口,实际的操作却由函数func_impl执行,通过函数func_impl的参数类型推导,获取到Iterator指向对象的类型T,从而解决了问题。

 

 

问题2:以迭代器所指对象的类型,声明返回类型

即如果需要返回类型是迭代器所指对象的类型??

 

解决方法:内嵌声明类型,即在迭代器内部添加一种“特性”(traits).

 

template<typename T>

class Iterator

{

public:

    typedef  T value_type; //内嵌类型声明(特性)

    Iterator(T *p = 0) : m_ptr(p) {}

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

    //...

 

private:

    T *m_ptr;

};

 

template<class Q, class P>

typename Q::value_type  //以迭代器所指对象的类型作为返回类型,长度有点吓人! !!

func(P iter)

{

   return *iter;

}

 

int main(int argc, const char *argv[])

{

    Iterator<int> iter(new int(10));

    cout<<func(iter)<<endl;  //输出:10

}

 

函数func()的返回类型前面必须加上关键词typename 因为T是一个template参数,编译器在编译实例化func之前,对T一无所知,就是说,编译器并不知道Iterator<T>::value_type是一个类型,或者是一个静态成员函数,还是一个静态数据成员,关键词typename的作用在于告诉编译器这是一个类型,这样才能顺利通过编译。

但是这种解决方法,并不能完全解决问题,对于原生指针,也是一种迭代器,但是无法内嵌类型。对于这种问题的解决方法,是针对原生指针做特殊化处理,即利用模版偏特化(在声明特化版本之前一定要有非特化版本的声明)

 

问题3:原生指针 迭代器萃取机

原生指针:即普通类型的指针,如int *,char *,等系统内嵌类型的指针。

利用原生指针+迭代器萃取机获得原生指针所指对象的类型。

 

template<class T>

class It{};

 

template<typename T>

class It<T*>

{

};

 

这个特化版仅适用于T为原生指针的情况,“T为原生指针”就是“T为任何类型”的一个更进一步的条件限制。

 

在STL中使用iterator_traits这个结构来专门“萃取”迭代器的特性。

Template<typename Iterator>

Struct iterator_traits

{

typedef typename Iterator::value_type value_type;

}

 

利用iterator_traits来萃取迭代器所指对象类型。

Template<typename It>

Typename iterator_traits<It>::value_type

Fun(It t)

{

Return *t;

}

 

因此,根据上述。就可以写出针对迭代器是原生指针的iterator_traits的偏特化版本。

 template<class T>//声明

 struct iterator_trait{};

 

 template<class T>

 struct iterator_trait<T*>//针对原生指针的偏特化处理

 {//传入T类型的指针,根据模版参数推导获得T的确切类型

 typedef T value_type;

 };

以及利用偏特化处理的iterator_trait,所以可以改写针对原生指针的偏特化处理:

 template<class T>//T为传入的原生指针

 typename iterator_trait<T>::value_type

 fun(T t)

 {

 return *t;

 }

 

 

但是,如果T为const修饰的原生指针时,就会出现,当我们想用iterator_trait萃取出value_type并声明一个临时变量时,却发现声明的变量是const类型,并不能赋值(指针所指对象为const型,指针本身可变)。

为解决这个问题,我们需要一种方法区别const和非const型原生指针的偏特化版本。为此,只需要再设计一个iterator_trait偏特化版本即可。

 template<class T>//声明

 struct iterator_trait{};

 

 template<class T>//针对const型原生指针的偏特化处理

 struct iterator_trait<const T *>

 {

 typedef T value_type;

 };

 

 

问题4iterator_trait中定义的类型

 

STL中定义了迭代器常用的五种类型:value_type、difference_type、pointer、reference、iterator_category。

 

STL中iterator_traits的完整定义如下:

tempalte<typename I>

struct iterator_traits

{

    typedef typename I::iterator_category iterator_category;

    typedef typename I::value_type value_type;

    typedef typeanme I:difference_type difference_type;

    typedef typename I::pointer pointer;

    typedef typename I::reference reference;

};

 

其中:

1)value_type 迭代器所指对象的类型。

2)difference_type 两个迭代器之间的距离。以C++中ptrdiff_t为原型。

3)reference_type 迭代器所指对象的类型的引用。

4)pointer 迭代器所指的对象的相应指针。

5)iterator_category 表示迭代器的移动特性和可以对迭代器执行的操作。从iterator_category上,可将迭代器分为Input Iterator、Output Iterator、Forward Iterator、Bidirectional Iterator、Random Access Iterator.

 

为了保证iterator_traits可以正常工作,STL提供了一个iterator类,所有自定义的迭代器都必须继承自它,才能保证这些自定义的迭代器可以顺利的与其他STL组件进行写作。

 

类iterator不包含任何成员变量,只有类型的定义,因此不会增加额外的负担

 

 

 

 

 

参考:http://blog.csdn.net/shudou/article/details/10270971

0 0
原创粉丝点击