3 迭代器与概念和traits编程技法
每一种STL容器都有其专属迭代器。
3.4 Traits编程技法——STL源代码门钥
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;
};
template <class T>
struct iterator_traits<T*> { // 偏特化版 — 针对“迭代器是個原生指標”的情况
typedef T value_type;
};
template <class T>
struct iterator_traits<const T*> { // 偏特化版 — 當迭代器是個 pointer-to-const
typedef T value_type; // 萃取出來的型別應該是T 而非const T,value_type经常用于声明局部对象,不能使const
};
template <class I>
typename iterator_traits<I>::value_type // 這㆒整行是函数返回型別
func(I ite)
{ return *ite; }
1、value_type
2、difference_type
template <class I, class T>
typename iterator_traits<I>::difference_type // 這㆒整行是函式回返型別
count(I first, I last, const T& value) {
typename iterator_traits<I>::difference_type n = 0;
for ( ; first != last; ++first)
if (*first == value)
++n;
return n;
}
// 針對原生指针而設計的「偏特化(partial specialization)」版
template <class T>
struct iterator_traits<T*>{
...
typedef ptrdiff_t difference_type;
};
// 針對原生的pointer-to-const而設計的「偏特化(partial specialization)」版
template <class T>
struct iterator_traits<const T*> {
...
typedef ptrdiff_t difference_type;
};
3、pointer和reference
// 針對原生指標而設計的「偏特化版(partial specialization)」
template <class T>
struct iterator_traits<T*>{
...
typedef T* pointer;
typedef T& reference;
};
// 針對原生的pointer-to-const而設計的「偏特化版(partial specialization)」
template <class T>
struct iterator_traits<const T*>{
...
typedef const T* pointer;
typedef const T& reference;
};
5、iterator_category
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 bidirectional_iterator_tag{ };
//以advance()举例
template <class InputIterator, class Distance>
inline void __advance(InputIterator& i, Distance n, input_iterator_tag)
{
// 單向,逐㆒前進
while (n--) ++i;
}
// 這是㆒個單純的轉呼叫函式(trivial forwarding function)。稍後討論如何免除之。
template <class ForwardIterator, class Distance>
inline void __advance(ForwardIterator& i, Distance n, forward_iterator_tag)
{
// 單純㆞進行轉呼叫(forwarding)
advance(i, n, input_iterator_tag());
}
template <class BidiectionalIterator, class Distance>
inline void __advance(BidiectionalIterator& i, Distance n, bidirectional_iterator_tag)
{
// 雙向,逐㆒前進
if (n >= 0)
while (n--) ++i;
else
while (n++) --i;
}
template <class RandomAccessIterator, class Distance>
inline void __advance(RandomAccessIterator& i, Distance n, random_access_iterator_tag)
{
// 雙向,跳躍前進
i += n;
}
//调用__advance(),传入的第三个参数是一个默认对象,仅仅为了使用重载机制。
template <class InputIterator, class Distance>
inline void advance(InputIterator& i, Distance n)
{
__advance(i, n, iterator_traits<InputIterator>::iterator_category());
}
// 針對原生指標而設計的「偏特化版(partial specialization)」
template <class T>
struct iterator_traits<T*> {
...
// 注意,原生指標是㆒種Random Access Iterator
typedef random_access_iterator_tag iterator_category;
};
// 針對原生的pointer-to-const而設計的「偏特化版(partial specialization)」
template <class T>
struct iterator_traits<const T*>
...
// 注意,原生的pointer-to-const 是㆒種Random Access Iterator
typedef random_access_iterator_tag iterator_category;
};
3.5 std::iterator的保证
STL提供了一个iterator class,每个新设计的迭代器只要继承自它,就可保证STL的规范。
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;
};
3.7 SGI STL的私房菜——__type_traits
双底线前缀词是指SGI STL内部所有的东西,不在STL标准范围之内。
isterator_traits负责萃取迭代器的特性,__type_traits则负责萃取型别的特性。
struct __true_type{ };
struct __false_type{ };
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; //Plain old data
};
/* 以㆘針對C++ 基本型別char, signed char, unsigned char, short,
unsigned short, int, unsigned int, long, unsigned long, float, double,
long double 提供特化版本。注意,每㆒個成員的值都是__true_type,表示這些
型別都可採用最快速方式(例如memcpy)來進行拷貝(copy)或賦值(assign)動
作。*/
//__STL_TEMPLATE_NULL 定义为template<>
__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 ForwardIterator, class Size, class T>
inline ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const 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 型別,就會派送(dispatch)到這裡
template <class ForwardIterator, class Size, class T>
ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T& x, __false_type) {
ForwardIterator cur = first;
// 為求閱讀順暢簡化,以㆘將原本有的異常處理(exception handling)去除。
for ( ; n > 0; --n, ++cur)
construct(&*cur, x); // 見2.2.3 節
return cur;
}
// 如果是POD 型別,就會派送(dispatch)到這裡。㆘兩行是原檔所附註解。
// 如果copy construction 等同於assignment,而且有trivial destructor,
// 以㆘就有效。
template <class ForwardIterator, class Size, class T>
inline ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T& x, __true_type) {
return fill_n(first, n, x); // 交由高階函式執行,如㆘所示。
}
// 以㆘是定義於<stl_algobase.h> ㆗的fill_n()
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;
}
究竟一个class什么时候该有自己的non-trivial default consructor,non-trivial copy consructor,non-trivial assignment operator,non-trivial destructor呢?一个判断准则是:如果class内含指针成员,并且对它进行内存动态配置,那么这个class就需要实现自己的non-trivial-xxx。