Traits编程技法

    迭代器所指对象的型别,称为该迭代器的value type。value type是迭代器相应型别的一种。想要知道迭代器的value type,下面是一种办法:

 1 template <class T>
 2 struct MyIter{
 3     typedef T value_type;
 4     T* ptr;
 5     //....
 6 };
 7 
 8 template <class I>
 9 typename I::value_type
10 func(I ite)
11 {  return *ite; }

 但当func参数为原生指针时上述办法就不适用了。偏特化可以解决,所谓partial specialization的意思是提供另一份template的定义,其本身仍为templatized。

1 template<typename T>
2 class C {  ...  };
3 
4 //特化版本,使用于T为原生指针
5 template<typename T>
6 class C<T*> {  ...  };

    专门定义一个class template用来萃取迭代器的特性:

1 template <class I>
2 struct iterator_traits {
3     typedef typename I::value_type value_type;
4 };

 这样使用iterator_traits<I>::value_type,实际上就是I::value_type,使用:

1 template <class I>
2 typename iterator_traits<I>::value_type
3 func(I ite)
4 {  return *ite; }

可以针对原生指针提供一个特化版本:

1 template <class T>
2 struct iterator_traits<T*> {
3     typedef T value_type;
4 };

故即使原生指针int*不是一种class type,仍可以通过iterator_traits<int*>::value_type萃取出其value type。

    根据经验,最常用到的迭代器相应型别有五种:

1 template <class I>
2 struct iterator_traits {
3     typedef typename I::iterator_category iterator_category;
4     typedef typename I::value_type value_type ;
5     typedef typename I::difference_type difference_type ;
6     typedef typename I::pointer pointer ;
7     typedef typename I::reference reference ;
8 };

iterator_traits必须针对传入之型别为pointer及pointer-to-const者,设计特化版本。


iterator_category

    迭代器可以分为五类:

    Input Iterator:只读。

    Output Iterator:只写。

    Forward Iterator

    Bidirectional Iterator

    Random Access Iterator

上述的迭代器前两种往后依次强化,即后者支持前者支持的操作,且支持新的操作(前三种支持operator++,第四个加上operator--,最后一个涵盖所有指针的能力)。设计算法时,针对某种迭代器提供一个明确的定义,并针对更强化的某种迭代器提供另一种定义。例如,有个算法可以接受Forward Iterator,Random Access Iterator给它当然也可以接受,但由于算法在实现时只使用了Forward Iterator支持的操作,没有使用Random Access Iterator支持的更加便捷的操作,会导致效率低,故应该再定义一个Random Access Iterator版本的。

定义五个classes,代表五种迭代器类型:

1 struct input_iterator_tag { };
2 struct output_iterator_tag { };
3 struct forward_iterator_tag : public input_iterator_tag  { };
4 struct bidirectional_iterator_tag : forward_iterator_tag  { };
5 struct random_access_iterator_tag : bidirectional_iterator_tag  { };

 定义以下重载函数:

 1 template <class InputIterator, class Distance>
 2 inline void __advance(InputIterator& i, Distance n, input_iterator_tag)
 3 {
 4     while (n--)  ++i;
 5 }
 6 
 7 template <class BidirectionalIterator, class Distance>
 8 inline void __advance(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag)
 9 {
10     if (n >= 0)
11         while (n--)  ++i;
12     else
13         while (n++)  --i;
14 }
15 
16 template <class RandomAccessIterator, class Distance>
17 inline void __advance(BidirectionalIterator& i, Distance n, random_access_iterator_tag)
18 {
19     i += n;
20 }

 每个__advance()的最后一个参数都只声明参数的类型,并未制定参数名称,因为它只是用来激活重载,函数里用不到该参数。接下来需要一个对外的接口,它接受两个参数,当它准备调用__advance()时,加上第三个参数:迭代器类型,这个工作要依赖于traits机制:

1 template <class InputIterator, class Distance>
2 inline void advance(InputIterator& i, Distance n)
3 {
4     __advance(i, n, iterator_traits<InputIterator>::iterator_category());
5 }

traits除了上面提供的class的迭代器类型,针对指针的特化版本:

 1 template <class T>
 2 struct iterator_traits<T*> {
 3      ...
 4      typedef random_access_iterator_tag iterator_category ;
 5  };
 6 
 7 template <class T>
 8 struct iterator_traits<const T*> {
 9      ...
10      typedef random_access_iterator_tag iterator_category ;
11  };

STL算法的一个命名规则:以算法所能接受之最低阶迭代器类型,来为其迭代器型别参数命名。

__type_traits

    STL只对迭代器加以规范,制定出iterator_traits,SGI把这种技法进一步扩大,于是有了__type_traits:

1 template <class type>
2 struct __type_traits {
3     typedef __true_type  this_dummy_member_must_be_first;
4     typedef __false_type  has_trivial_default_constructor;
5     typedef __false_type  has_trivial_copy_constructor;
6     typedef __false_type  has_trivial_assignment_operator;
7     typedef __false_type  has_trivial_destructor;
8     typedef __false_type  is_POD_type;
9 };

特化版本:

 1 template <class type>
 2 struct __type_traits<char> {
 3     typedef __true_type  has_trivial_default_constructor;
 4     typedef __true_type  has_trivial_copy_constructor;
 5     typedef __true_type  has_trivial_assignment_operator;
 6     typedef __true_type  has_trivial_destructor;
 7     typedef __true_type  is_POD_type;
 8 };
 9 
10 template <class type>
11 struct __type_traits<signed char> {
12     typedef __true_type  has_trivial_default_constructor;
13     typedef __true_type  has_trivial_copy_constructor;
14     typedef __true_type  has_trivial_assignment_operator;
15     typedef __true_type  has_trivial_destructor;
16     typedef __true_type  is_POD_type;
17 };
18 
19 template <class type>
20 struct __type_traits<unsigned char> {
21     typedef __true_type  has_trivial_default_constructor;
22     typedef __true_type  has_trivial_copy_constructor;
23     typedef __true_type  has_trivial_assignment_operator;
24     typedef __true_type  has_trivial_destructor;
25     typedef __true_type  is_POD_type;
26 };
27 
28 template <class type>
29 struct __type_traits<short> {
30     typedef __true_type  has_trivial_default_constructor;
31     typedef __true_type  has_trivial_copy_constructor;
32     typedef __true_type  has_trivial_assignment_operator;
33     typedef __true_type  has_trivial_destructor;
34     typedef __true_type  is_POD_type;
35 };
36 
37 template <class type>
38 struct __type_traits<unsigned short> {
39     typedef __true_type  has_trivial_default_constructor;
40     typedef __true_type  has_trivial_copy_constructor;
41     typedef __true_type  has_trivial_assignment_operator;
42     typedef __true_type  has_trivial_destructor;
43     typedef __true_type  is_POD_type;
44 };
45 
46 //后面省略int, unsigned int, long, unsigned long, float, double, long double, T*.....

使用示例:

 1 template <class T> inline void copy(T* source, T* destination, int n){
 2     copy(source, destination, __type_traits<T>::has_trivial_copy_constructor());
 3 }
 4 
 5 template <class T> inline void copy(T* source, T* destination, int n, __false_type)
 6 {  ...  }
 7 
 8 //拷贝一个数组,其元素具有trivial copy constructors,可借助memcpy()
 9 template <class T> inline void copy(T* source, T* destination, int n, __true_type)
10 {  ...  }