迭代器学习(一)
《STL 源码剖析》中,第三章叫“迭代器概念与traits编程技法”。总共33页,我艰难的读了一遍,愚蠢的我还是被所谓“traits技法”惊呆了!说白了,想要真正明白迭代器,就必须了解traits编程技术。
但不忙,在看什么是traits之前,先看看什么叫“迭代器”:迭代器是一种设计模式,他要求提供一种方法,使之能够一次访问某个聚合物内部的元素,而又无需暴露该聚合物内部的表达方式。也就是说,迭代器就是一个不需要知道聚合物内部实现细节而又可以访问聚合物内部元素的东西!
那迭代器有什么用呢?特别是在STL里面,迭代器扮演着什么样的角色呢?
在STL里面,容器与算法是分开设计的,容器是容器,算法是算法,那我们要是想在容器里面用算法可怎么办呢?难不成还需要实现一个特殊版本的内部算法?那岂不是会造成大量的代码冗余,无论谁看都不雅啊!
那,解决一个问题,就需要了解问题的本质,那上面这个问题的本质是什么呢?也就是说,我们用在容器里面使用算法,需要什么?我相信谁都知道,一个算法只有用在数据之上才有价值,也就是说,只要我们能够操作容器的数据,就可以使用算法来做一些事情,这时候,迭代器就排上用场了,再想想迭代器的概念,是不是有种首尾呼应的感觉呢?
好了,明白了这个简单的道理,就要去啃一个难点,就是traits编程技术,那我们需要了解什么叫traits编程技术,需要说明的一点是,我觉得某位老师说的一句话非常对:“概念是最大的认知障碍”,也就是,当我们在没有明白什么叫什么的前提下去学习什么,那么会非常困难,如果在做事情之前了解什么叫什么,那事情就会变得容易得多。
所以,首先,什么叫traits编程技术呢?在看了书,查资料之后,我觉得下面的定义较为妥当:traits编程技术就是通过模板的类型推导机制,获得变量的类型,而后决定dispatch到哪个函数。
为什么需要traits技术呢?因为c++是弱类型的,所以没有所谓typeof,只要sizeof,但sizeof之后又不能确定类型,因为sizeof(bool)==sizeof(char)你有什么办法,当然如果硬要实现的话,可能真的可以也说不定,就是麻烦点,但是依靠c++中的模板类型推导机制,可以快速方便的获得类型,这不是更好嘛?
在讨论更加深入的内容之前,还需要在讲一个东西,那就是指针,根据迭代器的概念,指针也可以算是一种迭代器,但很明显指针不是类,那就没有办法依靠模板类型推导来得到变量的具体类型了,那怎么办呢?没事,加上一个特化版本就可以了。
又来了,什么叫特化版本呢?其实原来叫”partial specialization”,意思是提供另一分template定义,而其本身仍为templatized。
好了,再次整理traits技术,更加通俗易懂一点,traits就是一个“特性萃取器”,来什么,就可以提取出是什么类型,好厉害!
在标准STL里面,有5种最常用的迭代器,下面对这些迭代器做一些简要介绍:
(1)、value_type ,即迭代器所指对象的型别
(2)、difference_type ,用来表示两个迭代器之间的距离,他可以用来表示一个容器的最大容量但要求是这个迭代器具有连续空间
(3)、reference_type,引用
(4)、pointer_type,指针
(5)、iterator_category,迭代器类别
上面第五个提到的迭代器类型,说是迭代器类别?这是什么鬼?不急,我们先来看看迭代器的类别再说话:
(1)、Input_iterator,这种迭代器所指向的对象,不允许外界改变,只读
(2)、Output_iterator,只写
(3)、Forward_iterator,读写操作都可以,单向
(4)、Bidirectional_iterator,可双向移动
(5)、Random_access_iterator,随机的啊
现在我们应该明白了吧,iterator_category就是上面五种迭代器类型之中的一个。
好了,有了上面介绍的这些知识,可以怀着忐忑的心情去看STL的源代码了。下面是对文件
//下面是五种迭代器类型,仅仅是作为标记用,没有任何成员,所以不会有任何负担
//其中使用了继承
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 {};
template <class T, class Distance> struct input_iterator {
typedef input_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
struct output_iterator {
typedef output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
};
template <class T, class Distance> struct forward_iterator {
typedef forward_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T, class Distance> struct bidirectional_iterator {
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T, class Distance> struct random_access_iterator {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
//要是想开发自己的迭代器,最好继承下面这个类吧,因为没有什么东西,所以不会造成什么压力
#ifdef __STL_USE_NAMESPACES
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;
};
#endif /* __STL_USE_NAMESPACES */
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
//下面就开始展示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_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
};
//针对原声指针做的特化版本
template <class T>
struct iterator_traits<T*> {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
//针对原声常量指针做的偏特化版本
template <class T>
struct iterator_traits<const T*> {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
};
//这个函数将很容易的决定某个迭代器的类型
template <class Iterator>
inline typename iterator_traits<Iterator>::iterator_category //返回类型
iterator_category(const Iterator&) {
typedef typename iterator_traits<Iterator>::iterator_category category;
return category();
}
//返回迭代器的difference_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>::value_type*
value_type(const Iterator&) {
return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
}
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
template <class T, class Distance>
inline input_iterator_tag
iterator_category(const input_iterator<T, Distance>&) {
return input_iterator_tag();
}
inline output_iterator_tag iterator_category(const output_iterator&) {
return output_iterator_tag();
}
template <class T, class Distance>
inline forward_iterator_tag
iterator_category(const forward_iterator<T, Distance>&) {
return forward_iterator_tag();
}
template <class T, class Distance>
inline bidirectional_iterator_tag
iterator_category(const bidirectional_iterator<T, Distance>&) {
return bidirectional_iterator_tag();
}
template <class T, class Distance>
inline random_access_iterator_tag
iterator_category(const random_access_iterator<T, Distance>&) {
return random_access_iterator_tag();
}
template <class T>
inline random_access_iterator_tag iterator_category(const T*) {
return random_access_iterator_tag();
}
template <class T, class Distance>
inline T* value_type(const input_iterator<T, Distance>&) {
return (T*)(0);
}
template <class T, class Distance>
inline T* value_type(const forward_iterator<T, Distance>&) {
return (T*)(0);
}
template <class T, class Distance>
inline T* value_type(const bidirectional_iterator<T, Distance>&) {
return (T*)(0);
}
template <class T, class Distance>
inline T* value_type(const random_access_iterator<T, Distance>&) {
return (T*)(0);
}
template <class T>
inline T* value_type(const T*) { return (T*)(0); }
template <class T, class Distance>
inline Distance* distance_type(const input_iterator<T, Distance>&) {
return (Distance*)(0);
}
template <class T, class Distance>
inline Distance* distance_type(const forward_iterator<T, Distance>&) {
return (Distance*)(0);
}
template <class T, class Distance>
inline Distance*
distance_type(const bidirectional_iterator<T, Distance>&) {
return (Distance*)(0);
}
template <class T, class Distance>
inline Distance*
distance_type(const random_access_iterator<T, Distance>&) {
return (Distance*)(0);
}
template <class T>
inline ptrdiff_t* distance_type(const T*) { return (ptrdiff_t*)(0); }
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
template <class InputIterator, class Distance>
inline void __distance(InputIterator first, InputIterator last, Distance& n,
input_iterator_tag) {
while (first != last) { ++first; ++n; }
}
template <class RandomAccessIterator, class Distance>
inline void __distance(RandomAccessIterator first, RandomAccessIterator last,
Distance& n, random_access_iterator_tag) {
n += last - first;
}
template <class InputIterator, class Distance>
inline void distance(InputIterator first, InputIterator last, Distance& n) {
__distance(first, last, n, iterator_category(first));
}
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
__distance(InputIterator first, InputIterator last, input_iterator_tag) {
iterator_traits<InputIterator>::difference_type n = 0;
while (first != last) {
++first; ++n;
}
return n;
}
template <class RandomAccessIterator>
inline iterator_traits<RandomAccessIterator>::difference_type
__distance(RandomAccessIterator first, RandomAccessIterator last,
random_access_iterator_tag) {
return last - first;
}
template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last) {
typedef typename iterator_traits<InputIterator>::iterator_category category;
return __distance(first, last, category());
}
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
template <class InputIterator, class Distance>
inline void __advance(InputIterator& i, Distance n, input_iterator_tag) {
while (n--) ++i;
}
#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma set woff 1183
#endif
template <class BidirectionalIterator, class Distance>
inline void __advance(BidirectionalIterator& i, Distance n,
bidirectional_iterator_tag) {
if (n >= 0)
while (n--) ++i;
else
while (n++) --i;
}
#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma reset woff 1183
#endif
template <class RandomAccessIterator, class Distance>
inline void __advance(RandomAccessIterator& i, Distance n,
random_access_iterator_tag) {
i += n;
}