C++ STL迭代器相应型别的推导总结

来源:互联网 发布:mac epub mobi 转换 编辑:程序博客网 时间:2024/09/21 08:56

在算法设计中,经常需要获取迭代器的相应型别,即迭代器所指对象的类型。C++中的RTTI typeid()可以获取型别的名称,但是无法拿它用来声明对象。

这里总结以下迭代器相应型别的获取方法。

一 利用function template的参数推导机制(argument deducation)

template <class I,class T>void func_impl(I iter,T t){    T tmp;}template <class T>inline void func(I iter){    func_impl(iter,*iter);}int main(){    int i;    func(&i);}
这个方法主要通过对迭代器解引用,得到迭代器所指对象,然后将迭代器和迭代器解引用后的对象,这两个参数传入func_impl函数之中,然后由编译器自动进行模板的参数推导,从而获取迭代器的相应型别。然而这种template参数推导机制方法并不适用于任何的情况,比如函数的返回值就无法利用这种方法,因为template参数推导只适合于参数,不适合于函数返回值。所以我们需要更加全面的方法。

二 声明内嵌型别

先看例子:

#include<iostream>using namespace std;template <class T>struct MyIter{typedef T value_type;T* ptr;MyIter(T* p=0):ptr(p){}T& operator*() const{return *ptr;}};template <class I>typename I::value_type func(I iter){return *iter;}int main(){MyIter<int>iter(new int(8));cout<<func(iter);//输出8 }
其中func的返回值必须加上关键字typename,因为T是一个template参数,在它编译具现化之前,编译器对T一无所知,编译器此时并不知道MyIter<T>::value_type代表的是一个型别或者是一个member function或是一个data member。typename的用意是告诉编译器这是一个型别,才能通过编译。但是这种方法只适用于迭代器是一个class或者struct,因为只有class和struct才能使用内嵌型别即typedef T value_type;而对于像指针这种类型,这种方法不使用。怎么办呢,这时候模板偏特化就派上用场了。


三 模板偏特化

模板偏特化的定义:

提供另一份template的定义式,而本身仍然是一个class template,是针对任何template参数更进一步的条件限制所设计出来的一个特化版本。

template <typename T>class C{}; template <typename T>class C<T*>{};
上面的第二个版本是第一个版本的偏特化,是对T这种任何型别的模板进一步的限制,只能适用于T*这种原生指针类型。

有了偏特化之后,就可以解决上面的原生指针不是class type的类型。我们可以针对“迭代器的template参数为指针”者,设计特化版本的迭代器。

#include<iostream>using namespace std;template <class T>struct MyIter{typedef T value_type;T* ptr;MyIter(T* p=0):ptr(p){}T& operator*() const{return *ptr;}};//偏特化 template <class T>struct MyIter<T*>{typedef T value_type;T* ptr;MyIter(T* p=0):ptr(p){}T& operator*() const{return *ptr;}};template <class I>typename I::value_type func(I iter){return *iter;}int main(){MyIter<int>iter1(new int(8));MyIter<int*>iter2(new int(8));//注释掉偏特化版本将出错 cout<<func(iter1)<<endl<<func(iter2); } 
为了方便,我们可以继续添加一个类模板,来萃取迭代器的模板类型。

template<class T>struct my_iterator_traits{typedef typename T::value_type value_type;//注意必须有typename};//对原生指针T偏特化template<class T>struct my_iterator_traits<T*>{typedef  T value_type;};//对指向常对象的原生指针偏特化template<class T>struct my_iterator_traits<const T*>{typedef T value_type;};
第二个和第三个版本可以萃取处原生指针的相应类型,对于const T*类型如果没有定义第三个版本,则第二个版本会把它萃取成const T。为了更好的萃取T类型,于是就定义了第三个版本。

下面是完整的程序:

#include<iostream>using namespace std;template <class T>struct MyIter{typedef T value_type;T* ptr;MyIter(T* p=0):ptr(p){}T& operator*() const{return *ptr;}};//偏特化template <class T>struct MyIter<T*>{    typedef T value_type;    T* ptr;    MyIter(T* p=0):ptr(p){}    T& operator*() const{        return *ptr;    }};template<class T>struct my_iterator_traits{typedef typename T::value_type value_type;//注意必须有typename};//对原生指针T偏特化template<class T>struct my_iterator_traits<T*>{typedef  T value_type;};//对指向常对象的原生指针偏特化template<class T>struct my_iterator_traits<const T*>{typedef T value_type;};template <class I>typename my_iterator_traits<I>::value_type func(I iter){return *iter;}int main(){MyIter<int>iter1(new int(8));MyIter<int*>iter2(new int(8));cout<<func(iter1)<<endl<<func(iter2);}

若要让my_iterator_traits有效工作,必须对所有的迭代器都定义相应型别即value_type。各自都定义一个内嵌类型。不定义的就无法进入STL这个体系。

STL中常见的5中相应型别如下:

template<class T>struct my_iterator_traits{typedef typename T::iterator_category iterator_category;//迭代器分类 typedef typename T::value_type value_type;//相应型别 typedef typename T::difference_type difference_type;//两个迭代器之间的距离 typedef typename T::pointer pointer;//指针 typedef typename T::reference reference;//引用 }; 







0 0
原创粉丝点击