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);
}
这里是以func为对外的接口,实际操作在func_impl里面,这样的话可以由一个类型推导出多个相关的类型,还实现了较好的封装性。
因为模板(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;
}
typename的意思是告诉编译器这是一个类型,这样才能顺利通过编译
但是这样只能接受类,不能接受内置的类型,举个例子
//===============不支持原生指针的版本===
#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;
}
这里的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 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;
}