STL源码-iterator traits编程技法

本文详细介绍了C++ STL中的iterator_traits结构体以及Traits编程技术。通过typename关键字来处理模板中依赖于类型参数的名称,确保它们被解析为类型。文中讨论了在不同场景下typename的使用限制,并展示了如何通过iterator_traits获取迭代器的value_type、difference_type等属性,以及在实际编程中如何利用这些属性进行类型推断和迭代器类型的分类。
  1. typedef typename iterator_traits<_Iter>::value_type  value _type;  

1:简介typename

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

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

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

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

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

2:Traits编程技术

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

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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. templates <class T>  
  2. struct Iterator   
  3. {  
  4. typedef T value_type;//内嵌型别声明  
  5. ...  
  6. };  
  7.   
  8. template <class Iterator>  
  9. typename Iterator::value_type //返回值类型  
  10. GetValue(Iterator iter)   
  11. {  
  12.     return *iter;  
  13. }  
  14.   
  15. int main()  
  16. {  
  17.     ...  
  18.     Iterator<int> ite(new int(9));  //<可以知道value_type是int,那么GetValue最后也是返回int类型
  19.     std::cout<<GetValue(ite)<<std::endl;  
  20.     return 0;  
  21. }  
          在用户自定义类型中我们可以通过内嵌型别获得返回值的类型,若不是用户自定义的类型,而是内置类型时,例如是原生指针,这时候该怎么处理呢?因为原生指针不能内嵌型别声明,所以内嵌型别在这里不适用。于是Traits技术就出现了。以下利用Traits技术也可以获取用户自定义类型的返回值类型。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. template <class Iterator>  
  2. struct iterator_traits {  
  3.   typedef typename Iterator::value_type    value_type;  //<运用了typename 这个变量表示这是一个型别
  4.   ...  
  5. };  
  6.   
  7. template <class Iterator>  
  8. typename iterator_traits<Iterator>::value_type //返回值类型  
  9. GetValue(Iterator iter)   
  10. {  
  11.     return *iter;  
  12. }  
     以上这种方法对原生指针不可行,所以 iterator_traits 针对原生指针的一个版本就应运而生。下面是针对 *Tp const *Tp 的版本,也称为 iterator_traits 版本的偏特化iterator_traits的偏特化版本解决了原生指针的问题现在不管迭代器是自定义类模板, 还是原生指针(Tp*, const Tp*),struct iterator_traits都能萃取出正确的value type类型。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. template <class Tp>  
  2. struct iterator_traits<Tp*> {  
  3.   typedef Tp       value_type;  
  4.   ...  
  5. };  
  6.   
  7. template <class Tp>  
  8. struct iterator_traits<const Tp*> {  
  9.   typedef Tp       value_type;  //<我们需要提取的是non-const类型,提取一个不能复制的变量没有任何意义
  10.   ...  
  11. };  

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


3: 5中迭代器

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. template <class _Iterator>  
  2. struct iterator_traits {  
  3.   typedef typename _Iterator::iterator_category iterator_category; //迭代器类型  
  4.   typedef typename _Iterator::value_type        value_type;     //迭代器所指对象的类型  
  5.   typedef typename _Iterator::difference_type   difference_type;//迭代器之间距离  
  6.   typedef typename _Iterator::pointer           pointer;        //迭代器所指之物  
  7.   typedef typename _Iterator::reference         reference;      //迭代器引用之物  
  8. };  

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值