STL——Traits编程技法
文章目录
偏特化的意义
如果class template
拥有一个以上的template
参数,我们可以针对其中某个(或数个,但非全部)参数template
进行特化工作。
所谓partial specialization
的意思是提供另一份template
定义式,而其本身仍为templatized
。《泛性思维》书中对partial specialization
的定义是"针对(任何)template
参数更进一步的条件限制所设计出来的一个特化版本"。
template<typename T>
class C { ... }; //这个泛化版本允许(接受)T为任何类型
很容易接受它有一个形式如下的 partial specialization
:
template<typename T>
class C<T*>{ ... }; //这个特化版本仅适用于“T为原生指针”的情况
//“T为原生指针”便是“T为任何类型”的更进一步的条件限制
特性萃取机
下面这个class template
专门用来“萃取”迭代器的特性,而value type
正是迭代器的特性之一
template<class T>
struct iterator_traits{ //traits意为“特性”
typedef typename I::value_type value_type;
};
这个所谓的traits
,其意义是,如果 I
定义有自己的value type
,通过这个traits
的作用,萃取出来的value_type
就是I::value_type
。
图上说明traits
所扮演的“特性萃取机”角色,萃取各个迭代器的特性,这个迭代器特性,指的是迭代器的相应型别。
最常用的迭代器相应型别有五种:value type,difference type,pointer,reference,iterator catagory。
template<class I>
struct iterator_traits
{
typedef typename I::iterator_category iterator_category;
typedef typename I::value_type value_type;
typedef typename I::difference_type difference_type;
typedef typename I::pointer pointer;
typedef typename I::reference reference;
};
value_type
所谓value type
,就是指迭代器所指对象的类型。
difference type
difference type
用来表示两个迭代器之间的距离,因此它可以用来表示一个容器的最大容量。对于连续空间的容器而言,头尾之间的距离就是其最大容量。如果一个泛型算法提供计数功能,例如count()
,其传回值就必须适用迭代器的difference_type
。
reference type
迭代器所引用的类型
int* pi = new int(5);
const int* pci = new int(9);
*pi = 7; //对mutable iterator进行解引用操作时,获得的应该是左值,允许赋值
*pci = 1; //这个操作不允许,因为pci是一个constant iterator
如果p
是一个constant iterator
,其value type
是T
,那么*p
的型别不应该是const T
,而是const T&
。如果p
是mutable iterator
时,如果其value type
是T
,那么*p
的类型是T&
。
pointer type
迭代器所指的类型
template<class T>
struct iterator_traits{
...
typedef typename I::pointer pointer;
typedef typename I::reference reference;
}
//针对原生指针而设计的“偏特化版”
template<class T>
struct iterator_traits<T*>
{
...
typedef T* pointer;
typedef T& reference;
};
//针对原生的pointer-to-const而设计的“偏特化版”
struct iterator_traits<const T*>
{
...
typedef const T* pointer;
typedef const T& reference;
};
iterator_category
迭代器所属的类别
input_iterator,output_iterator,forward iterator,bidirectional iterator,random access iterator;
template<class T>
struct iterator_traits{
...
typedef typename I::iterator_category iterator_category;
}
//针对原生指针而设计的“偏特化版”
template<class T>
struct iterator_traits<T*>
{
...
typedef =random_access_iterator_tag iterator_category;
};
//针对原生的pointer-to-const而设计的“偏特化版”
struct iterator_traits<const T*>
{
...
typedef =random_access_iterator_tag iterator_category;
};
iterator源代码
//5种迭代器类型
struct input_iterator_tag { };
struct output_iterator_tag { };
struct forward_iterator_tag : public input_iterator_tag { };
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidireactional_iterator_tag {};
template<class Category, class T, class Distance=ptrdiff_t, class Pointer = T*, class Reference = T&>
struct iterator{
typedef Category iterator_category;
tyepdef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
};
//榨汁机traits
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;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
};
//针对原生指针而设计的traits偏特化版
template<class T>
struct iterator_traits<T*>{
typedef typename random_access_iterator_tag iterator_category;
typedef typename T value_type;
typedef typename ptrdiff_t difference;
typedef typename T* pointer;
typedef typename T& reference;
};
//针对原生指针而设计的traits偏特化版
template<class T>
struct iterator_traits<const T*>{
typedef typename random_access_iterator_tag iterator_category;
typedef typename T value_type;
typedef typename ptrdiff_t difference;
typedef typename T* pointer;
typedef typename T& reference;
};
//这个函数可以很方便的决定某个迭代器的类型(category)
template <class Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&){
typedef typename iterator_traits<Iterator>::iterator_category category;
return category();
}
//这个函数可以很方便的决定某个迭代器的distance type
template <class Iterator>
inline typename iterator_traits<Iterator>::difference_type*
distance_type(const Iterator&){
return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);
}
//这个函数可以很方便的决定某个迭代器的value type
template <class Iterator>
inline typename iterator_traits<Iterator>::difference_type*
distance_type(const Iterator&){
return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
}
type_traits
type_traits
负责萃取类型的特性。此处我们所关注的类型特性是指:这个类型是否具备 non-trivial defalt ctor
(默认构造函数),non-trivial copy ctor
(拷贝构造函数),non-trivial assignment operator
(拷贝赋值运算符)和 non-trivial dtor
(析构函数)。如果答案是否定的,我们在对这个类型进行构造,析构,拷贝,赋值等操作时,就可以采用最有效率的措施,采用内存直接处理操作如malloc,memcpy
等等,获得最高效率。
在程序中,可以这样运用__type_traits<T>
,T
代表任意类型。
__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
值,应该是个有着真/假性质的“对象”,因为我们希望可以利用其返回结果进行参数推导,而编译器只有面对class object
形式的参数,才会做参数推导。为此,上述式子应该传回这样的东西;
struct __true_type {};
struct __false_type {};
对于某些类型
__STL_TEMPLATE_NULL struct __type_traits<int>
{
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;
};
__STL_TEMPLATE_NULL struct __type_traits<long>
{
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;
};
__STL_TEMPLATE_NULL struct __type_traits<float>
{
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;
};
__STL_TEMPLATE_NULL struct __type_traits<double>
{
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;
};
//针对原生指针而设计__type_traits“偏特化版”
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;
};
如果我们定义了一个Shape类,也可以针对这个Shape设计type_traits的特化版本。
template<> struct __type_traits<Shape>{
typedef __true_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;
};