首页 > 代码库 > STL Traits编程技法

STL Traits编程技法

traits编程技法大量运用于STL实现中。通过它在一定程度上弥补了C++不是强型别语言的遗憾,增强了C++关于型别认证方面的能力。

traits编程技法是利用“内嵌型别”的编程技法和编译器的template参数推导功能实现的。

 

iterator_traits

1.对于class type要求其“内嵌型别”

    要求与STL兼容的容器,其迭代器必须定义一下五种型别:

   iterator_category  迭代器类型

   value_type  迭代器所指对象类型

   difference_type  迭代器间的距离类型

   pointer

   reference

2.对于非class type(如:原生指针)需要使用template partial specialization(偏特化)

 1 //class type的“内嵌型别”
 2 template <class _Iterator>
 3 struct iterator_traits {
 4   typedef typename _Iterator::iterator_category iterator_category;
 5   typedef typename _Iterator::value_type        value_type;
 6   typedef typename _Iterator::difference_type   difference_type;
 7   typedef typename _Iterator::pointer           pointer;
 8   typedef typename _Iterator::reference         reference;
 9 };
10 
11 //对原生指针的偏特化
12 template <class _Tp>
13 struct iterator_traits<_Tp*> {
14   typedef random_access_iterator_tag iterator_category;
15   typedef _Tp                         value_type;
16   typedef ptrdiff_t                   difference_type;
17   typedef _Tp*                        pointer;
18   typedef _Tp&                        reference;
19 };
20 
21 //对const指针的偏特化
22 template <class _Tp>
23 struct iterator_traits<const _Tp*> {
24   typedef random_access_iterator_tag iterator_category;
25   typedef _Tp                         value_type;
26   typedef ptrdiff_t                   difference_type;
27   typedef const _Tp*                  pointer;
28   typedef const _Tp&                  reference;
29 };

 

iterator中为什么要引入traits机制?

提高效率

对效率的至极追求贯穿整个STL设计,traits机制的引入是为了实现 同一方法用于不同类型时调用对该类型最高效的版本 以提高效率。

例如 advance():

 1 //用于input_iterator的版本
 2 template <class _InputIter, class _Distance>
 3 inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {
 4   while (__n--) ++__i;
 5 }
 6 
 7 //用于 bidirectional_iterator的版本
 8 template <class _BidirectionalIterator, class _Distance>
 9 inline void __advance(_BidirectionalIterator& __i, _Distance __n, 
10                       bidirectional_iterator_tag) {
11   __STL_REQUIRES(_BidirectionalIterator, _BidirectionalIterator);
12   if (__n >= 0)
13     while (__n--) ++__i;
14   else
15     while (__n++) --__i;
16 }
17 
18 //用于 random_access_iterator的版本
19 template <class _RandomAccessIterator, class _Distance>
20 inline void __advance(_RandomAccessIterator& __i, _Distance __n, 
21                       random_access_iterator_tag) {
22   __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
23   __i += __n;
24 }
25 
26 //advance方法的对外接口
27 template <class _InputIterator, class _Distance>
28 inline void advance(_InputIterator& __i, _Distance __n) {
29   __STL_REQUIRES(_InputIterator, _InputIterator);
30   __advance(__i, __n, iterator_category(__i));
31 }

 

SGI STL中迭代器之外的 __type_traits

STL只对迭代器进行了traits规范,制定类iterator_traits。SGI 把这种规范扩大到类迭代器之外,也就是__type_traits(__前缀表示是SGI 内部使用的,不在STL规范内)。

iterator_traits负责萃取iterator特性,而__type_traits则负责萃取一下五种型别(type)特性:

  has_trivial_default_constructor  是否有平凡的默认构造函数

  has_trivial_copy_constructor  是否有平凡的拷贝构造函数

  has_trivial_assignment_operator  是否有平凡的分配操作

  has_trivial_destructor  是否有平凡的析构函数

  is_POD_type  是否为POD类型(POD:Plain Old Data)

如果class内含指针成员,并对它进行内存动态分配,那么这个class就需要实现自己的 non-trivial-xxx。

上述特性应该响应我们“真”或“假”,但却不能是bool值,因为我们要利用其响应来进行参数推导,而编译器只有面对class object形式的参数时才能进行参数推导,因此响应应该是带有“真”“假”性质的不同类。SGI STL中如下定义:

1 struct __true_type {
2 };
3 
4 struct __false_type {
5 };
 1 template <class _Tp>
 2 struct __type_traits { 
 3    typedef __true_type     this_dummy_member_must_be_first;
 4                    /* Do not remove this member. It informs a compiler which
 5                       automatically specializes __type_traits that this
 6                       __type_traits template is special. It just makes sure that
 7                       things work if an implementation is using a template
 8                       called __type_traits for something unrelated. */
 9 
10    /* The following restrictions should be observed for the sake of
11       compilers which automatically produce type specific specializations 
12       of this class:
13           - You may reorder the members below if you wish
14           - You may remove any of the members below if you wish
15           - You must not rename members without making the corresponding
16             name change in the compiler
17           - Members you add will be treated like regular members unless
18             you add the appropriate support in the compiler. */
19  
20 
21    typedef __false_type    has_trivial_default_constructor;
22    typedef __false_type    has_trivial_copy_constructor;
23    typedef __false_type    has_trivial_assignment_operator;
24    typedef __false_type    has_trivial_destructor;
25    typedef __false_type    is_POD_type;
26 };

为保守起见都定义为__false_type

 

在SGI STL的Type_traits.h中对C++ 内建的bool/char/signed char/unsigned char等标记为__true_type。

 

为什么要引入__type_triats?

答案还是提高效率

对于标记为__true_type的型别,对其对象进行构造/析构/拷贝/赋值等操作时就可以采用最有效率的措施。(如:不必调用高层次的constructor/destructor,而采用内存直接处理操作malloc()/memcpy()等)