traits编程技法

模板函数的参数推导机制:
eg:
template<typename I, typename T>
void func(I iter, T t)
{
 T tmp;
 ...;
}
void main()
{
 int i;
 func(&i,i);//模板函数可以通过参数的推导机制推导出实际的函数为void func  

  //(int*,int);
}
可能有的人看到模板函数之后会高兴的手舞足蹈,但是该技巧虽然可用于value_type,但是却非全面

可用。玩意value_type必须用于函数的传回值,就束手无策了,毕竟模板参数推导机制推导的仅仅是

参数而已,无法推导函数的返回值型别。

这就造成一个严重的问题,试想一个算法如果需要返回value_type型别的返回值,通过模板参数推导

机制是无法实现的。在这种情况下,我们何不在迭代器的实作当中将该类型保存起来呢??既然如此,

我们来看看c++标准库的实作手法。
template<typename T>
struct MyIter
{
 typedef T value_type;//内嵌型别声明
 T *ptr;//迭代器实体
 MyIter(T* p=0):ptr(p){}
 T& operator*(){return *ptr);
}
//下面为实作算法,返回型别为迭代器所指对象的型别
template<typename I>//I在此应该为一种迭代器型别
typename I::value_type
GetValue(I)
{
 return* I;//返回迭代器所指的对象
}
注意:GetValue的回返型别必须加上关键词typename,因为T是一个template参数,在它被编译器具

现化之前,编译器对T一无所悉,换句话说,编译器并不知道MyIter<T>::value_type代表的是一个型

别或是一个member function或是一个data member。关键词typename意在告诉编译器这是一个型别,

如此才能通过编译。

但是这里有一点我们还没有考虑到,我们在这里假设的是迭代器是一种类类型,classtype,但是所

有人都因该知道仅仅这是不够的,因为原生指针就不是如此,STL必须接受原生指针作为一种迭代器

,于是就出现了偏特化
eg:
template<typename T>
class C{};//这个泛化版本允许接受T为任何型别
template<typename T>
class C<T*>{};//该泛化版本仅适用于"T为原生指针"的情况

回忆一下,我们已经定义了迭代器,算法,再看看萃取器
template<typename T>//萃取器
struct iterator_traits
{
 typedef typename T::value_type value_type;
}

template<typename T>//算法
typename iterator_traits<T>::value_type
func(T iter)
{
 return *iter;
}
可能有人会说,萃取器比前面没用萃取器多什么,仅仅是多了一个层次的封装,其实除了这个意义外

,好处是traits可以拥有特化版本,哈哈。。。
eg:
template<typename T>
struct iterator_traits<T*>
{
 typedef T value_type;
}

template<typename T>
struct iterator_traits<const T*>
{
 typedef T value_type;
}
在此,有了萃取器,我们可以很容易的萃取出迭代器的响应型别,当然了,首先你必须遵循迭代器的

定义规则,必须将响应的内嵌型别定义出来。
最常用的迭代器响应型别有5种。
template<typename T>
struct iterator_traits
{
 typedef typename T::value_type value_type;
 typedef typename T::pointer pointer;
 typedef typename T::reference reference;
 typedef typename T::difference_type difference_type;
 typedef typename T::iterator_category iterator_category;//这是一个很重要的型别,

对于算法来说很重要,有时候不同的迭代器在算法中采取的是不同的版本,这样在算法里面就需要进

行判断,如果用if语句来判断,由于这样会在执行期进行判断影响效率,于是在算法中进行重载函数

将该变量作为一个参数传递
}
最后,我们来总结一下c++标准库的发展过程:
1.函数模板参数推导机制,完成了参数的推导,无法对返回型别进行推导
2.为了解决前述问题,出现了内嵌型别,将迭代器型别嵌入到一个称为类类型的结构体中,但无法解

决原生指针的特殊问题,因为原生指针不是类类型
3.于是出现了模板的偏特化

总结:traits编程技法大量运用于stl实现中,它利用“内嵌型别”的编程技巧与表一起的template

参数推导功能,增强c++未能提供的关于型别认证方面的能力,弥补c++不为强型别语言的遗憾。

posted @ 2011-04-17 19:32  luck_net  阅读(353)  评论(0编辑  收藏  举报