您的位置:首页 > 编程语言

STL源码-iterator traits编程技法

2014-12-28 22:25 399 查看
1:简介typename

typename iterator_traits<_Iter>::value_type是类型名;但是感到困惑的是这里为什么要使用typename关键字?

typename在C++类模板或者函数模板中经常使用的关键字,此时作用和class相同,只是定义模板参数

typename在下面情况下禁止使用:

模板定义之外,即typename只能用于模板的定义中
非限定类型,比如int,vector<int>之类
基类列表中,比如template <class T> class C1 : T::InnerType不能在T::InnerType前面加typename
构造函数的初始化列表中

如果类型是依赖于模板参数的限定名,那么在它之前必须加typename(除非是基类列表,或者在类的初始化成员列表中)。

2:Traits编程技术
在STL编程中,容器和算法是独立设计的,即数据结构和算法是独立设计的,连接容器和算法的桥梁就是迭代器了,迭代器使其独立设计成为可能。Traits编程技术是STL中最重要的编程技术,Traits可以获取一个类型的相关信息。

若我们要知道用户自定义类型的函数返回值类型,我们可以使用内嵌型别技术就可以知道返回值的类型;看下面程序:

[cpp] view
plaincopy





templates <class T>

struct Iterator

{

typedef T value_type;//内嵌型别声明

...

};



template <class Iterator>

typename Iterator::value_type //返回值类型

GetValue(Iterator iter)

{

return *iter;

}



int main()

{

...

Iterator<int> ite(new int(9));
//<可以知道value_type是int,那么GetValue最后也是返回int类型

std::cout<<GetValue(ite)<<std::endl;

return 0;

}

在用户自定义类型中我们可以通过内嵌型别获得返回值的类型,若不是用户自定义的类型,而是内置类型时,例如是原生指针,这时候该怎么处理呢?因为原生指针不能内嵌型别声明,所以内嵌型别在这里不适用。于是Traits技术就出现了。以下利用Traits技术也可以获取用户自定义类型的返回值类型。

[cpp] view
plaincopy





template <class Iterator>

struct iterator_traits {

typedef typename Iterator::value_type value_type;
//<运用了typename 这个变量表示这是一个型别

...

};



template <class Iterator>

typename iterator_traits<Iterator>::value_type //返回值类型

GetValue(Iterator iter)

{

return *iter;

}

以上这种方法对原生指针不可行,所以iterator_traits针对原生指针的一个版本就应运而生。下面是针对*Tp和const
*Tp的版本,也称为iterator_traits版本的偏特化。iterator_traits的偏特化版本解决了原生指针的问题。现在不管迭代器是自定义类模板,
还是原生指针(Tp*, const Tp*),struct iterator_traits都能萃取出正确的value
type类型。

[cpp] view
plaincopy





template <class Tp>

struct iterator_traits<Tp*> {

typedef Tp value_type;

...

};



template <class Tp>

struct iterator_traits<const Tp*> {

typedef Tp value_type;
//<我们需要提取的是non-const类型,提取一个不能复制的变量没有任何意义

...

};

我们之所以要萃取(Traits)迭代器相关的类型,就是要把迭代器相关的类型用于声明局部变量、用作函数的返回值等一系列行为。对于原生指针和point-to-const类型的指针,采用模板偏特化技术对其进行特殊处理。要使用Traits功能,则必须自行以内嵌型别定义的方式定义出相应型别。我们上面讲解的只是迭代器其中一种类型value
type,在迭代器中还有其他类型

3: 5中迭代器

[cpp] view
plaincopy





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; //迭代器引用之物

};

1.value type 迭代器所指向的对象的类型 比如说 vector<int >::iterator it; 那么 value type 的值为 int

2.difference type 可以表示两个迭代器之间的距离 ,比如说,可以用这种类型来计数, 如,typename iterator_traits<I>::difference_type n =0, for(I first ; first != end; ++first ) n++; //n这种变量可做计数,算容量

3.reference type 引用类型,

4.pointer type 指针类型

5.iterator _category 迭代器本身的类型 (详情看下一小节),这个内部类型可以用于标识本身的类型,可用函数重载时候的版本识别, 所有重载时候的版本识别:主要是由于迭代器有5大类,无疑random_access_iterator 的功能是最强大的,但是并不是每次都是用最强大的一个版本性能就是最高的,由于其功能强大了,无疑内部实现会复杂一点,既有可能性能会有所下降,不过相当多的迭代器都是Random Access iterator 这种类型的,如果一个算法find()能够接受一个input_iterator,那么给它Random
Access iterator 未必最好,因此,可以实现接受五个版本 的迭代器类型 find()函数,按需选择,(注意不要使用动态绑定,这样会大大减低性能),可以在算法中find(Iterator , iterator tag),加入一个用于识别的参数,然后通过,iterator_traits<Iterator >::category萃取出来这个category类型,可以实现函数版本识别

5中是迭代器:

input iterator:只读

output iterator 只写

forward iterator 单向,读写,只能向前++ 多继承于 input iterator,output iterator

bidirectional iterator 双向读写 可++ - - 继承于 forward iterator

Random Access iterator 随即读 可 +n -n 操作写继承于 bidirectional iterator

[cpp] view
plaincopyprint?





#include<iostream>

#include<vector>

#include<list>

#include<deque>

#include<iterator>



using namespace std;

//下面定义5个版本的func函数,为了简单起见,就一个参数,分别表示不同的迭代器类型

void func(random_access_iterator_tag)

{

cout<<"random_access_terator 类型的迭代器"<<endl;

}



void func(bidirectional_iterator_tag)

{

cout<<"bidirectional_terator 类型的迭代器"<<endl;

}



void func(forward_iterator_tag)

{

cout<<"forward_terator 类型的迭代器"<<endl;

}



void func(input_iterator_tag)

{

cout<<"input_terator 类型的迭代器"<<endl;

}

void func(output_iterator_tag)

{

cout<<"output_terator 类型的迭代器"<<endl;

}

//这里提供一个接口给用户使用fun()

template<class InputIterator >



void fun(InputIterator it)

{//这句代码最关键,利用iterator_traits<IputIterator>萃取出 iterator_category属性

typedef iterator_traits<InputIterator>::iterator_category category;

func(category()); //调用去萃取

}



int main()

{

vector<int> ve ;

for(int i = 0;i<10;i++)

ve.push_back(i);



int cc=5;

int *d = &cc; //第一个迭代器,指向int 类型

//第二个迭代器

vector<int>::iterator a = ve.begin();

//第三个迭代器

std::istream_iterator<int> is ;

//分别对其调用fun函数

fun(d);

fun(a);

fun(is);





system("pause");

return 0;

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: