一、概述
第二章中提到了__typr_traits(),在STL中它的作用是提取对象(可能是类,可能是指针或引用)的型别。第三章中对它用到的traits编程技巧进行了详细的介绍。首先从针对迭代器的特例iterator_traits入手,然后再延伸至可以提取任意对象型别的__type_traits。
总结一下的话,__type_traits获取对象型别的特性是<strong>template参数推导</strong>、<strong>内嵌型别声明</strong>与<strong>template偏特化</strong>(针对指针和指向常量的指针)结合起来的产物。
二、迭代器
STL的整体思想是将数据容器与算法分离开彼此独立设计,这两个独立体之间的粘合剂,就是迭代器。
迭代器本质上是一种智能指针,参照C++标准对智能指针auto_ptr的定义,获取其所指对象的型别是必需的操作。这就要求我们在设计迭代器时必须设计一种机制,可以获得这一型别。于是iterator_traits就诞生了。(每个容器都有其特定的迭代器,这是封装性的一种体现,具体原因参考p84)
2.1 类对象值型别(value_type)的提取
如何实现呢,对于类对象来说,其型别通过内嵌对象声明和template推导就可得到。
2.1.1 类对象value_type示例
template <class T>
struct MyIter{ //迭代器的设计,由容器设计者进行设计
typedef T value_type; //内嵌型别声明
//...
};
template <class I>
typename I::value_type //调用时通过template参数推导可知返回的具体类型(必须加上typename声明它是一个型别而不是成员函数或是成员变量)
func(I ite){ //算法的设计
//...}
2.2 指针所指对象值型别(type_value)的提取
内嵌型别声明+template参数推导可以得到类对象的型别,对于(原生)指针来说就不可取。因为这种方法得不到我们想要的指针指向对象的型别。利用偏特化机制可以做到这点。
2.2.1 指针value_type示例
template <class T>
struct MyIter{ //迭代器的设计,由容器设计者进行设计
typedef T value_type; //内嵌型别声明
//...
}
template <class I>
struct iterator_traits{ //为了利用偏特化特性,貌似"多此一举"声明的这个类是必需的
typedef typename I::value_type;
}
template <class I>
typename iterator_traits<I>::value_type //实际iterator_traits情形
func(I ite){ //算法的设计
//...
}
//针对原生指针和指向常量的指针的偏特化
template <class I>
struct iterator_traits<I*>{ //提取所指对象的型别
typedef I value_type;
}
template <class I>
struct iterator_traits<const I*>{ //提取所指对象的型别
typedef I value_type;
}
2.3 其他迭代器感兴趣的对象型别
除了值型别(value_type)外,迭代器感兴趣的型别还有4种:iterator_type、difference_type、pointer与reference。见2.3.1节。
2.3.1 其他对象型别示例
template <class I>
struct iterator_traits{
typedef typename I::iterator_category iterator_category;
typedef typename I::value_type value_type;
typedef typename I::diference_type difference_type;
typedef typename I::pointer pointer;
typedef typename I::reference reference;
}
//相应的偏特化版本
template <class I>
struct iterator_traits<T*>{
//iterator_category比较特殊,见1.3.1节
typedef typename I::iterator_category iterator_category;
typedef I value_type;
typedef ptrdiff_t difference_type;
typedef I* pointer;
typedef I& reference;
}
template <class I>
struct iterator_traits<const T*>{
//iterator_category比较特殊,见2.3.1节
typedef typename I::iterator_category iterator_category;
typedef I value_type;
typedef ptrdiff_t difference_type;
typedef I* pointer;
typedef I& reference;
}
2.3.2 iterator_category型别
迭代器自身是可以分成五类的,分类根据是迭代器对相应容器元素访问的能力强弱(例如FI比II能力强,FI包含II所有的访问方式,它们之间的关系可以考虑成继承关系)。
因为迭代器是容器与算法的粘合剂,所以书中以advance()算法为例说明iterator_category的设计与实现:
//iterator父类
template <class Category,
class T,
class Distance = ptrdiff_t,
class Pointer = T*,
class Reference = T&>
struct iterator{
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
}
//iterator的每个具体实现都继承iterator父类
template <class T>
struct MyIter
:public std::iterator<std::forward_iterator_tag, Item>
{
//...
};
//用于标记的型别
struct input_iteartor_tag { };
struct output_iteartor_tag { };
struct forward_iteartor_tag : public input_iterator_tag{ };
struct bidirectional_iteartor_tag : public forward_iterator_tag{ };
struct random_access_iteartor_tag : public bidirectional_iterator_tag{ };
template <class InputIterator, classs Distance> //以算法可接受最低阶迭代器类型命名
inline void advance(InputIterator& i, Distance n){
__advance(i, n,
iterator_traits<InputIterator>::iterator_category()); //临时对象
}
template <class T>
struct iterator_traits{
typedef typename I::iterator_category iterator_category;
//...
};
//针对原生指针的偏特化设计,原生指针是一种random access iterator
template <calss T>
struct iterator_traits<T*>{
typedef random_access_iterator_tag iterator_category;
}
template <calss T>
struct iterator_traits<cosnt T*>{
typedef random_access_iterator_tag iterator_category;
}
//多个__advance()版本
template <class RandomIterator, class Distance>
inline void __advance(RandomIterator &i, Distance n, random_access_iterator_tag())
{ //... };
template <class ForwardIterator, class Distance>
template <class InputIterator, class Distance>
//等等其他版本
三、__type_traits类型提取
__type_traits类型提取,我们关注的是对象的trivial性质:它是否有trivial default ctor、copy ctor、assignment operator与dtor,以及它类型是否为POD类型。站在程序员的视角来判断这些性质是相对容易的:若class中含有指针成员,并对它进行了内存动态配置,那么这个class是需要实现它的non-trivial-xxx的。
然而站在程序角度确实不同的,这就需要使用一种额外的机制来判断它的trivial性质,于是__type_traits横空出世了。
3.1 __type_traits示例
struct __true_type {};
struct __false_type {};
//类模板
template<class types>
struct __type_traits{
//为了处理编译器自身含有__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_assianment_operator;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
};
//针对每一个支持类型的特化(char、int、long等等)
template <>
struct __type_traits<char>{
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assianment_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_assianment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
3.2 以unintialized_fill_n为例来看__type_traits是如何使用的
//获得迭代器指代对象的型别
template <class Iterator>
inline typename iterator_traits<Iterator>::valuetype*
value_type(const iterator& i){
return static_cast<typename iterator_traits<Iterator>::value_type*>(i);
}
template<class ForwardIterator, class Size, class T>
inline ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, cnst T& x){
return __uninitialized_fill_n(first, n, x, 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());
}
//函数重载
//若不为POD型,则不可避免的要使用default ctor、copy ctor、assignmant operator和dtor
template <class ForwardIterator, class Size, class T>
ForwardIterator
__unintialized_fill_n_aux(ForwardIterator first, Size n, const T& x, __false_type){
ForwardIterator cur = first;
for(;n > 0; --n, ++cur)
construct(&*cur, x);
return cur;
}
//若不为POD型,则调用高阶fill_n(),使用malloc或memcpy来避免ctor、dtor的昂贵开销
template <class ForwardIterator, class Size, class T>
inline ForwardIterator
__uninitialized_fill_n_aux(ForwardIterator forst, Size n, const T& x, __true_type){
return fill_n(first, n, x);
}
template<class OutputIterator, class Size, class T>
OutputIterator fill_n(OutputIterator first, Size n, const T& value){
for(;n > 0; --n, ++first)
*first = value;
return first;
}
注脚
这些读书笔记均为平时读书时随手记录下来的,之前一直分散在各处,特此将它们集中在一起,便于今后复习用。