什么是迭代器iterators,迭代器就类似于原生指针,比如char* p。它最重要的便是内容提领和成员访问。通过迭代器能够依次序巡访某个容器中的各个元素,但是又无需暴漏该容器的内部表述方式。考虑字符型指针p,我们可以通过指针的移动来访问到字符串中的各个元素。迭代器就类似于原生指针,但是其实现却是以类的方式来实现的。
STL对每一个迭代器都提供了专属的迭代器。
迭代器的实现使用了大量的函数模板或类模板。在实现的过程中,要使用到associatedtype即相应型别。相应型别就是迭代器所指的型别,联想若迭代器是int*,那么相应型别就是int。迭代器的实现中,有声明相应型别的变量的需求。若但是获取相应型别,我们可以使用typeid。但typeid仅仅是能够获取到该型别的名称,并不能用来声明变量类型实例。
如下面的代码:
//-------------1-------------------------------------- /*若T为指针,不能够定义出其所指类型的实例的一种情况*/ /******************************************************/ template<typename T1,typename T2> void function(T1 a,T2 b) { /*确实是没有办法来声明 T1所指的对象型别*/ T1* c; /*这里声明的是指针的指针*/ T1 d; /*这里声明的是指针*/ /* 照道理来讲,应该是声明为*T1才对。但显然,这个用法不对的 */ cout<<typeid(a).name()<<endl; cout<<typeid(b).name()<<endl; cout<<typeid(c).name()<<endl; cout<<typeid(d).name()<<endl; } /******************************************************/
上面的例子中,若T1是个指针,想想是不是没有办法在函数中去声明一个T1所指类型的变量实例。T1*c这种c为指向指针的指针,T1 d这种为指针。
为了实现能够声明相应型别的变量,这里使用的小技巧就是借助模板的参数推导机制,推导出相应型别。
//-------------2-------------------------------------- /*这里T为对象指针,而I则为指针所指对象的类型*/ template<typename T,typename I> void function_impl2(T a,I b) { I x; //这里使用了一个小技巧,就是使用到了模板的参数推导机制 cout<<typeid(a).name()<<endl; cout<<typeid(b).name()<<endl; cout<<typeid(x).name()<<endl; } //-------------3-------------------------------------- template<typename T,typename I> I function_impl(T a,I b) //这里也是由模板的参数推导机制,推出I为int了 这并不是说明模板参数推导机制 { //能够推出参数返回值类型。而是参数类型仍旧是由参数推导出来的 I x=b; cout<<typeid(a).name()<<endl; cout<<typeid(b).name()<<endl; cout<<typeid(x).name()<<endl; return x; } template<typename I> void function1(I c) { function_impl(c,*c); }
以上就是使用了模板参数推导机制,实现了在代码中声明相应型别的功能。但模板参数推导机制,仅仅能够推导出函数参数,却不能推导出函数返回值。像代码段3,出看以为这不是能够使用相应型别来做为返回值类型吗?但是请仔细看看,这种方法实际上还是借助了模板的参数推导机制。
那么如何解决这样的问题呢?答案是声明内嵌型别。
如下代码:
//-------------4-------------------------------------- //这种方法没有使用模板的参数推导机制,而是使用了内嵌型别 template<typename T> struct MyIterator { typedef T value_type;//声明内嵌型别 T* ptr; MyIterator(T* p=0):ptr(p) {} T& operator*() const {return *ptr;} }; /* 从这里可以看出我们讲迭代器使用起来就像指针,但实际上它不是一个真正的指针。而实际上是封装了一个原生指针的类。就像上面的MyIterator一样。在MyIterator中 我们可以使用typedef来定义内嵌类型。但是原生指针则不行了。因为它就是一个指针,而不是一个类。我们不能在哪个地方去定义MyIterator的内嵌类型。 */ template<typename I> typename I::value_type function2(I ite) { return *ite; } 这样的实现,对于我们的迭代器是够用的,因为我们的迭代器以类的方式实现。但是对于原生指针就不行了,比如int*。它就是一个指针,并且没有地方去声明内嵌型别。 为了使之对内嵌型别也适用。这里要对上述的代码进行改进,如下: //-------------5-------------------------------------- //从原理上来讲,应该是这样声明的。但不知道为何编译不过去 //这就是所谓的类型萃取器。 //可以看到,它比上面的实现仅仅是对了一层封装。但是这样的封装,能够让我们来使用偏特化,去偏特化原始指针来设计特化的版本 template<typename MyIterator> struct iterator_traits { typedef typename MyIterator::value_type value_type; }; template<typename T> typename iterator_traits<T>::value_type function3(T ite) { return *ite; }
一眼所见,不就是进行了简单的一层封装吗?但是正是这层封装使得我们能够对原生指针进行特化而解决上述的问题。
最终我们通过类模板的偏特化。无论是对于原生指针还是类型迭代器,我们都能够方便地取出相应型别。这就是类型萃取器的主要功能。
本人享有博客文章的版权,转载请标明出处 http://blog.csdn.net/baidu20008