STl-traits编程技巧
无论是泛型思想或者是STL(标准库)的实际运用,迭代器(iterators)都扮演着重要的作用。STL的中心思想是:将容器和算法分开,彼此独立设计,最后再讲他们融合在一起。
容器和算法的泛型设计并不难,使用C++的类模板(class tempalte)和成员模板(function template)就能完成。
但要是将两者融合在一起,你还需要掌握一些其他的技巧,比如成员模板的参数推导,声明内置类型,还有最重要的偏特化技巧。
要提取变量的类型,我们先使用函数模板的参数推导
template< class T, class U> void func_impl(T t, U u) { U temp; } template< class T> void func(T t) { func_impl(t, *t); }
因为模板(class template)只能推导参数,不能推导函数的返回类型,我们需要其他的技巧,声明内置类型就是一种不错的方法。
#include<iostream> using namespace std; template<class T> class MyIter { public: 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 ite)//这里I是MyIter, 返回类型是MyIter<T>里面T的类型,也就是int,有了typename和value_type,我们可以让返回值是任何类型都可以 { return *ite; //*ite指向的是int类型,根据T& operator*()const决定返回的类型 } void main() { MyIter<int> ite(new int(8)); cout<<func(ite)<<endl; }
但是这样只能接受类,不能接受内置的类型,举个例子
//===============不支持原生指针的版本=== #include<iostream> using namespace std; template<class T> class MyIter { public: 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 ite)//这里I是MyIter, 返回类型是MyIter<T>里面T的类型,也就是int,有了typename和value_type,我们可以让返回值是任何类型都可以 { return *ite; //*ite指向的是int类型,根据T& operator*()const决定返回的类型 } void main() { int *p=new int(5); MyIter<int> ite(p); cout<<func(p)<<endl;//错误,因为p没有value_type类型,在func的返回处typename I::value_type出错,因为不存在 }
使用原生的指针就会出错。
这个时候我们需要偏特化技术
//=============================偏特化和traits提取特性 #include<iostream> using namespace std; template<class T> class MyIter { public: typedef T value_type;//声明内嵌类型 T *ptr; MyIter(T *p=0):ptr(p) { } T& operator*()const { return *ptr; } }; template<class I> struct iterator_trait{ typedef typename I::value_type value_type;//提取出内嵌类型 }; //偏特化版本 template<class T> struct iterator_trait<T*> { typedef T value_type;//为了支持原生指针,即int等 }; template<class I> typename iterator_trait<I>::value_type func(I ite) { return *ite; } void main() { int *p=new int(8); MyIter<int> ite(p); cout<<func(ite)<<endl; }
最后还是一个问题,还要设计一个指向常数对象的指针版本
//=======================带指向常对象的指针 #include<iostream> using namespace std; template<class T> class MyIter { public: typedef T value_type;//声明内嵌类型 T *ptr; MyIter(T *p=0):ptr(p) { } T& operator*()const { return *ptr; } }; template<class I> struct iterator_trait{ typedef typename I::value_type value_type;//提取出内嵌类型 }; //偏特化版本 template<class T> struct iterator_trait<T*> { typedef T value_type;//为了支持原生指针,即int等 }; //针对指向常数对象的指针的偏特化版本 template<class T> struct iterator_trait<const T*> { typedef T value_type; }; template<class I> typename iterator_trait<I>::value_type func(I ite) { return *ite; } void main() { int *p=new int(8); const int c=7; const int*r=&c; MyIter<int> ite(p); cout<<func(r)<<endl; }