Chapter 3:迭代器概念以及 traits 编程技法

3.1:迭代器设计思维—STL关键所在

1:STL中心思想在于:将数据容器(container)与算法(algorithms)分开彼此独立设计,然后用迭代器(iterator)将它们撮合在一起;容器和算法的泛型化可用class template和function template分别达成目标;

2:算法find()这个例子展示了容器,算法和迭代器如何共同作用,该算法的源代码如下:

template <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& value)
{
    While(fist != last && *first != value)
        ++first;

    return first;
}

3.2:迭代器是一种smart pointer

1:迭代器是一种行为类似于指针的对象,其最重要的工作是内容提取(dereference)和成员访问(member access),因此迭代器编程工作中最重要的是对operator*operator->的重载(overloading);

2:迭代器对上述两个操作符重载的大概编码如下:

template <class T>
class iterator {
public:
    //...

    T& operator*() const { return *pointee; } //重载操作符operator*
    T* operator->() const { return pointee; } //重载操作符operator->

    //...
private:
    T* pointee

};

3:为了使STL容器类有更好的封装性,每一种STL容器都有自己的专属迭代器。

3.3:迭代器相应型别(associated types)以及traits编程技法

1:Partial Specialization(偏特化)

Partial Specialization大概的意思为:如果 class template 拥有一个以上的 template 参数,我们可以针对其中(或数个,但非全部)template 参数进行特化工作。其可以被如下定义:可以被理解为针对(任何)template 参数更进一步的条件限制所设计出来的一个特化版本。示例如下:

template<class T>
class C {...}; //这个泛化版本允许(接受)T 为任何型别

//上述类的一个特化版本如下:
template<class T>
class C<T*> {...}; //这个特化版本仅适用于”T为原生指针”的情况;
                   //"T为原生指针"便是“T为任何型别”的一个更进一步的条件限制;

2:迭代器相应型别(associated types)

最常用到的迭代器相应型别有五种,分别是 value type,difference type,reference type,pointer type 和 iterator_category,下面分别予以介绍:

1):value type

Value type 比较容易理解,指的是迭代器所指对象的型别;

2):difference type

Difference type 为 signed type,用来表示两个迭代器之间的距离。因此其可以用来表示一个容器的最大容量,因为对于连续空间的容器而言,头尾之间的距离就是其最大容量;原生指针(native pointer)的 difference type 为 ptrdiff_t(定义在 头文件中);

3):reference type 和 pointer type(引用类型)

Reference type 是指迭代器解引用(*iter)的型别;
Pointer type 是指迭代器所指的地址型别;

迭代器分为两种,一种是 mutable iterators,其所指的对象解引用后是能够被赋值的,比如说如果 p 是个 mutable iterator 并且其 value type 是 T,那么 p 的型别应是T&,这就是迭代器 p 的 reference type,同时迭代器 p 的 pointer type 为 T ;另外一种迭代器为 constant iterators,其所指对象为 const 常量,不能被改变,因此其 reference type 为 cosnt T&,并且其 pointer type 为 const T*;

4):iterator_category

(1):迭代器被分为如下5类:

I:Input Iterator:这种迭代器所指的对象,不允许外界改变,只读(read only);

II:Output Iterator:只写(write only);

III:Forward Iterator:允许 “写入型算法”,在此种迭代器所形成的区间上操作;

IV:Bidirectional Iterator:可双向移动;

V:Random Access Iterator:前四种迭代器都只供应一部分指针算术能力(前三种支持 operator++,第四种再加上operator--),Random Access Iterator则支持所有指针的算术操作,包括 p+n,p-n,p[n],p1-p2,p1

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 {};

之所以用类类型来表示这五类迭代器,是因为编译器需要仰赖它来进行重载决议(overloaded resolution)。

3:traits 编程技法

1):我们通过构造 iterator_traits 这个类来提取迭代器的上述五种相关型别(associated type),构造代码如下:

//针对 Iterator 为类这种情况
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;
};

//针对 Iterator 为原生指针(native pointer)而设计出来的 iterator_traits 的特化版本
template<class T>
struct iterator_traits<T*>
{
    typedef random_access_iterator_tag iterator_category;//原生指针的迭代器类型为 random access iterator;
    typedef T value_type;
    typedef ptrdiff_t difference_type;
    typedef T* pointer;
    typedef T& reference;
};

//针对原生指针为 pointer-to-const 而设计出来的 iterator_traits 的特化版本
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;
};

2):用类 iterator_traits 提取迭代器五种相关型别(associate types)的代码如下:

typename iterator_traits<I>::value_type; //提取迭代器的 value_type;
typename iterator_traits<I>::difference_type; //提取迭代器的 difference_type;
typename iterator_traits<I>::pointer; //提取迭代器的 pointer_type;
typename iterator_traits<I>::reference; //提取迭代器的 reference_type;
typename iterator_traits<I>::iterator_category; //提取迭代器的iterator_category;

3):通过类iterator_traits的定义,我们发现如果迭代器是类时,该类中一定要定义与其相关的五种型别,这是一个约定俗成的规则,如果谁不遵守这个规则,谁就不能兼容于 STL;

为了将事情简化,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;
};

类 iterator 不含有任何成员,纯粹只是型别定义,由于后三个参数皆有默认值,因此新的迭代器只需提供前两个参数即可,一个例子如下:

template <class T>
struct ex: public std::iterator<std::forward_iterator_tag, T>
{...};

3.4:适用于 SGI STL 的 __type_traits

1:如果说 iterator_traits 类负责提取迭代器的特性,则类 __type_traits 则负责提取型别(type)的特性,可以用来提取与型别相关的五个特性:has_trivial_default_constructor, has_trivial_copy_constructor, has_trivial_assignment_operator, has_trivial_destructor, is_POD_type

2:提取五个特性的回答是“真”与“假”,我们用类 __true_type 以及 __false_type 来表示真与假的回答,其构造如下:

struct __true_type{};
struct __false_type{};

这两个空白类中没有任何成员,不会带来额外负担,但又能表示真假;

3:我们可以通过构造类 __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;
}

但是需要注意的是:当我们用类 iterator_traits 来提取迭代器的相关型别时,我们是要求迭代器这个类中就要定义其相关型别;但是在用 __type_traits 来提取类型的特性时,我们不要求类型的定义中就要定义其相关型别,而是通过定义 __type_traits的特化版本来提取类型的特性,比如针对 int 类型的特化版本定义如下:

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;
}

但是现在有些编译器能够自动提供类别的相关特化版本,并不需要人为定义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值