Traits 编程

      最近看c++ STL迭代器一章,对于迭代器中的Traits编程技巧进行了一下研究,参考了一些博友们的博文和侯捷老师得STL源码剖析一书,对Traits编程做一下自己的表述。

     1、一些相关背景的介绍。

    假如一个程序设计者要写自己的一个容器,并且要让别人来对容器进行操作,除了必须要提供一些方法之外,还要设计一个自己的迭代器给用户使用,迭代器的设计者可以是用户,用户根据自己实际需要设计一个迭代器,但是这必须要求用户对容器内部的操作细节了如指掌,从封装性的角度来讲,使用容器的用户设计迭代器是一个很不好的设计。这时候就想到,让容器设计者设计一个迭代器,封装所有的细节,然后将这个迭代器作为一个外部接口,直接提供给用户使用。通俗一点说,我们的目的就是让用户从繁琐的细节中脱离出来,去做其它一些事情,而容器迭代器交给容器设计者去做。

2、迭代器相应的型别

所谓型别就是说迭代器所指的对象的类型,我们称之为value Type,在c++中只有sizeof(),而没有typeof(),型别的获得需要一些特殊的方法。c++提供的一种方法是函数模板得参数推导机制。例如:

template
void func_impl(I iter,T t)
{
T temp;
//do something
}
template
inline void func(I iter)
{
func_impl(iter,*iter);

}

int main()
{
int i;
func(&i);
return 0;
}

func函数对外提供了接口,但是其实现细节全部是放在func_impl()中,由于func_impl()是一个模板函数,当其被调用的时候,编译器会自动进行模板参数的推导,就能推导出T的类型,于是就解决了这个问题。但是这个时候存在这样带来两个问题:第一,在C++中一般存在五种常用型别,但是并不是所有型别都可以考模板参数推导推导出来;第二,当要推断函数返回值的时候,value Type就没办法了,毕竟模板参数推导不能推断函数的返回值。c++提供了一种方法,叫做声明内嵌型别。例如:

template
struct myIter
{
typedef T value_type;//内嵌型别声明
T *ptr;
myIter(T *p = 0):ptr(p){}
T& operator*()const {return *ptr}
};
template
typename I::value_type//声明函数的返回值
func(I ite)
{
return *ite;
}
//.......
myIter ite(new int(8));
std::cout<

从上述的例子可以看出来,并不是所有的迭代器都有class type。但是遇到指针的时候就没法了。STL规定,必须要接受指针作为一种迭代器,所以就使用了新的技巧来解决上面的问题。那就是模板偏特化。

3、模板偏特化

所谓模板偏特化,其实就是对同一个模板类,提供重载的版本,这个重载版本用于处理原指针。例如

template

class C {.........};//这是泛化版本,接受T为任何型别

template

class C {.........};//这是特化版本,用于处理原指针的情况

template

class C {.........};//这是特化版本,用于处理原指针的情况

这样,这个类就可以处理任何型别了,无论是value Type,还是像int*,const int*这样的类型了。有了模板得偏特化,我们就可以利用这个原理来说明Traits编程的思想了。

4、Traits编程技术

在STL中设计了一个类用来专门萃取迭代器的型别。

//泛化版本

template

struct iterator_traits

{

typedef typename T::value_type value_type;

};

//特化版本

template

struct iterator_traits

{

typedef T value_type;

};

template

struct iterator_traits

{

typedef T value_type;

};

相应的写一个函数,声明其返回值的时候就可以像如下这样书写:

template

typename iterator_traits::value_type      //特化版本,无论传入什么样的型别都可以

func(T ite)

{

//do something

}

总得来说,Traits是利用模板偏特化技术来实现对迭代器的型别的提取工作。其功能可以大致下图所示来表示




最后,要弄清Traits编程的优越性,需要知道得是,

(1)迭代器的设计是容器设计者的工作,不能让过多的细节暴露给用户;

  (2)  迭代器要处理所有的型别,包括value_type和原始指针;

  (3)Traits是运用模板的偏特化来实现的。




你可能感兴趣的:(原创,C++)