之前我们对iterator_traits有了一些了解,现在我们要了解__type_traits。
Iterator_traits负责萃取迭代器的特性,__type_traits则负责萃取型别的特性。
对于型别的特性,我们关注的点可能在于对该型别是否需要复杂处理。如果答案是否定的,我们在对这些型别进行构造、析构、拷贝赋值等操作时,就可以采取最有效率的措施,比如不使用析构函数,直接free等。
__type_traits提供了一种机制,允许针对不同的型别属性,在编译时期完成函数派送决定。这对于撰写template很有帮助。例如当我们对一个型别未知的数组进行copy时,如果我们事先知道该元素型别的构造函数是否是不重要的,我们可能可以使用memcpy或是memmove等函数快速处理
根据之前对于iterator_traits的学习,我们想必是希望与其有相同的形式可以使用:
- __type_traits<T>::has_trivial_default_constructor;
- __type_traits<T>::has_trivial_copy_constructor;
- __type_traits<T>::has_trivial_assignment_operator;
- __type_traits<T>::has_trivial_destructor;
- __type_traits<T>::is_POD_type;
且我们希望他们返回的是一个对象(或者说我们需要的是它的型别用以判断)而不是单纯的bool类型的值,可以帮助我们实现重载
- struct __true_type {
- };
- struct __false_type {
- };
STL对最初的__type_traits是这样处理的:
- template <class type>
- struct __type_traits {
- typedef __true_type this_dummy_member_must_be_first;
- //上面这个先不管
- 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;
- };
STL将所有类型的内嵌型别都定义为__false_type,这事STL给出的保守值,接下来我们会看到针对每一个型别设计的适当的__type_traits的特化版本
以下仅列出两个,其他类型的省略:
- __STL_TEMPLATE_NULLstruct __type_traits<char> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- //对于原生指针
- template <class T>
- struct__type_traits<T*> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
接下来,我们拿几个例子看看uninitialized_fill_n
首先,我们来看看全局函数
- template <class ForwardIterator, class Size, class T>
- inline ForwardIteratoruninitialized_fill_n(ForwardIterator first, Size n,
- const T& x) {
- return __uninitialized_fill_n(first, n, x, value_type(first));
- }
此函数在关于空间配置器的章节中见到过,用途也不多说了,就是在未初始化的空间内初始化n个x
可以看到,这里我们首先通过value_type(其实就是通过iterator_traits)得到了first类型中的value_type,即first的型别
接着:
- template <class ForwardIterator, class Size, class T, class T1>
- inline ForwardIterator__uninitialized_fill_n(ForwardIterator first, Size n,
- const T& x, T1*) {
- typedef typename __type_traits<T1>::is_POD_type is_POD;
- return __uninitialized_fill_n_aux(first, n, x, is_POD());
- }
再通过__type_traits得到该型别是否是POD类型
- //如果正是POD类型的话,只要简单的操作
- template <class ForwardIterator, class Size, class T>
- inline ForwardIterator
- __uninitialized_fill_n_aux(ForwardIteratorfirst, Size n,
- const T& x,__true_type) {
- return fill_n(first, n, x);
- }
- template <class OutputIterator, class Size, class T>
- OutputIteratorfill_n(OutputIterator first, Size n, const T& value) {
- for ( ; n > 0; --n, ++first)
- *first = value;
- return first;
- }
- //如果不是POD类型,那么就需要老老实实的一个一个在未初始化的内存中调用构造函数了!
- template <class ForwardIterator, class Size, class T>
- ForwardIterator
- __uninitialized_fill_n_aux(ForwardIteratorfirst, Size n,
- const T& x,__false_type) {
- ForwardIterator cur = first;
- __STL_TRY {
- for ( ; n > 0; --n, ++cur)
- construct(&*cur, x);
- return cur;
- }
- __STL_UNWIND(destroy(first, cur));
- }
再举一个例子,就是copy函数
最近一篇文章就是关于copy函数的笔记,所以详细的部分不再说了。
这里直接放在实例中进行:
- class C
- {
- public:
- //可见,此函数并没有operator= ,即it is a trival assignmentoperator
- C() :_date(3){}
- private:
- int _date;
- };
- void main()
- {
- C c[5];
- vector<C> Cc(c, c + 5);
- vector<C> Cd(5);
- copy(Cc.begin(), Cc.end(), Cd.begin());
- }
回顾之前对copy的学习,我们发现,对于copy内的函数调用的顺序是:
copy() ----- __copy_dispatch(T*, T*) ----- __copy_t(_false_type) ----- __copy_d
会调用__copy_dispatch(T*,T*)是因为在vector源代码中将iterator定义为类型的指针,并没有做任何处理。
然而为什么会是false_type呢?我们根据类的定义,根据语义,发现的确满足“具有不重要的assignmentoperator”,但返回的结果却依旧是false_type?
学了copy函数后,我们可能会对此感到疑惑,但当我们学过了本章__type_traits的源代码后,我们就可以清楚了知道,STL只对基础的型别进行了偏特化的处理,然而对于其他的型别则一律给予false_type的处理,除非我们自己定义这里类C的__type_traits,如下:
- __STL_TEMPLATE_NULLstruct __type_traits<C> {
- typedef __false_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __false_type is_POD_type;
- };
这样一来,如果再次执行,那么就是true_type了!