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

在算法设计中,经常需要获取迭代器的相应型别,即迭代器所指对象的类型。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;//引用 
}; 







  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值