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(偏特化)
//class type的“内嵌型别”
template <class _Iterator>
struct iterator_traits {
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
}; //对原生指针的偏特化
template <class _Tp>
struct iterator_traits<_Tp*> {
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef _Tp* pointer;
typedef _Tp& reference;
}; //对const指针的偏特化
template <class _Tp>
struct iterator_traits<const _Tp*> {
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef const _Tp* pointer;
typedef const _Tp& reference;
};
iterator中为什么要引入traits机制?
提高效率
对效率的至极追求贯穿整个STL设计,traits机制的引入是为了实现 同一方法用于不同类型时调用对该类型最高效的版本 以提高效率。
例如 advance():
//用于input_iterator的版本
template <class _InputIter, class _Distance>
inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {
while (__n--) ++__i;
} //用于 bidirectional_iterator的版本
template <class _BidirectionalIterator, class _Distance>
inline void __advance(_BidirectionalIterator& __i, _Distance __n,
bidirectional_iterator_tag) {
__STL_REQUIRES(_BidirectionalIterator, _BidirectionalIterator);
if (__n >= )
while (__n--) ++__i;
else
while (__n++) --__i;
} //用于 random_access_iterator的版本
template <class _RandomAccessIterator, class _Distance>
inline void __advance(_RandomAccessIterator& __i, _Distance __n,
random_access_iterator_tag) {
__STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
__i += __n;
} //advance方法的对外接口
template <class _InputIterator, class _Distance>
inline void advance(_InputIterator& __i, _Distance __n) {
__STL_REQUIRES(_InputIterator, _InputIterator);
__advance(__i, __n, iterator_category(__i));
}
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 };
template <class _Tp>
struct __type_traits {
typedef __true_type this_dummy_member_must_be_first;
/* Do not remove this member. It informs a compiler which
automatically specializes __type_traits that this
__type_traits template is special. It just makes sure that
things work if an implementation is using a template
called __type_traits for something unrelated. */ /* The following restrictions should be observed for the sake of
compilers which automatically produce type specific specializations
of this class:
- You may reorder the members below if you wish
- You may remove any of the members below if you wish
- You must not rename members without making the corresponding
name change in the compiler
- Members you add will be treated like regular members unless
you add the appropriate support in the compiler. */ typedef __false_type has_trivial_default_constructor;
typedef __false_type has_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_operator;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
};
为保守起见都定义为__false_type
在SGI STL的Type_traits.h中对C++ 内建的bool/char/signed char/unsigned char等标记为__true_type。
为什么要引入__type_triats?
答案还是提高效率
对于标记为__true_type的型别,对其对象进行构造/析构/拷贝/赋值等操作时就可以采用最有效率的措施。(如:不必调用高层次的constructor/destructor,而采用内存直接处理操作malloc()/memcpy()等)