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()等)