EffectiveC++学习笔记-条款47

条款47 请使用traits classes表现类型信息

请使用traits classes表现类型信息

这一条款主要来讨论模板中迭代器的属性iterator_category,它可以通过类似于vector::iterator::iterator_category的方式来取得。

到这里我们有必要学习一下STL迭代器的类型,总共有五种,分别是:

input_iterator:只读,只能逐个前移

output_iterator:只写,只能逐个前移

forward_iterator:可读可写,只能逐个前移

bidirectional_iterator:可读可写,支持逐个前移和后移

random_access_iterator:可读可写,支持随机访问(任意步数移动)

为了表明容器内使用的是哪一种迭代器,STL在定义迭代器会总会打个一个标记“tag”,每个tag都是一个空的结构体,对应于以上五种迭代器,tag也有五个:

struct input_iterator_tag{};

struct output_iterator_tag{};

struct forward_iterator_tag: public input_iterator_tag{};

bidirectional_iterator: public forward_iterator_tag{};

random_access_iterator: public bidirectional_iterator_tag{};

注意这五个tag之间,有些存在继承关系。

这个标记有什么用呢?STL在写vector的时候,会这样:

template class <T>
class vector
{
public:
    class iterator
    {
    public:
        typedef random_access_iterator iterator_category;
    }
}

写list的时候,会这样写:

template class <T>
class list
{
public:
    class iterator
    {
    public:
        typedef bidirectional_iterator iterator_category;
        …
    }
    …
}

既然迭代器已经由tag说明了它的类型(双向的,还是随机访问),那我们如何去利用它呢?比如现在我想要写一个迭代器前移的通用函数DoAdvance,不同迭代器类型会有不同的实现方式,所以我们可以像下面这样:

template <class T>
void DoAdvance(T Container)
{
    typedef T::iterator::iterator_category IteratorCategory;
    if (typeid(IteratorCategory) == typeid(input_iterator_tag))
    {
        cout << "Do manner in input_iterator_tag" << endl;
    }
    else if (typeid(IteratorCategory) == typeid(output_iterator_tag))
    {
        cout << "Do manner in output_iterator_tag" << endl;
    }
    else if (typeid(IteratorCategory) == typeid(forward_iterator_tag))
    {
        cout << "Do manner in forward_iterator_tag" << endl;
    }
    else if (typeid(IteratorCategory) == typeid(bidirectional_iterator_tag))
    {
        cout << "Do manner in bidirectional_iterator_tag" << endl;
    }
    else if (typeid(IteratorCategory) == typeid(random_access_iterator_tag))
    {
        cout << "Do manner in random_access_iterator_tag" << endl;
    }
}

参数T是容器的类型,比如vector,如果像下面这样调用:


vector<int> v;
DoAdvance(v);

那么输出是Do manner in random_access_iterator_tag,因为vector的迭代器是随机访问型的,可以按随机访问类型的处理方式来去实现前移操作。typeid返回结果是名为type_info的标准库类型的对象的引用,它指明了这个对象/定义的类型。

用法实例
#include <vector>  
#include <list>  
#include <deque>  
#include <iostream>  
using namespace std;

template<typename T>
struct Iterator_traits
{
    typedef typename T::value_type value_type;
    typedef typename T::iterator_category iterator_category;
};

template<typename T>
struct Iterator_traits<T*>
{
    typedef typename T::value_type value_type;
    typedef random_access_iterator_tag iterator_category;
};

template<typename T>
struct Iterator_traits<const T*>
{
    typedef typename T::value_type value_type;
    typedef random_access_iterator_tag  iterator_category;
};

#define VALUE_TYPE(I) Iterator_traits<I>::value_type()
#define ITERATOR_CATEGORY(I) Iterator_traits<I>::iterator_category()

//自定义的advance函数,与STL差不多  
template <class InputIterator, class Distance>
inline void MyAdvance(InputIterator &i, Distance n)
{
    _MyAdvance(i, n, ITERATOR_CATEGORY(InputIterator)); //萃取迭代器的类型  
}
template <class InputIterator, class Distance>
inline void _MyAdvance(InputIterator& i, Distance n, input_iterator_tag)
{
    while (n--) ++i;
    cout << "InputIterator" << endl;
}
template <class BidirectionalIterator, class Distance>
inline void _MyAdvance(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag)
{
    if (n >= 0)
        while (n--) ++i;
    else
        while (n++) --i;
    cout << "BidirectionalIterator" << endl;
}
template <class RandomAccessIterator, class Distance>
inline void _MyAdvance(RandomAccessIterator& i, Distance n, random_access_iterator_tag)
{
    i += n;
    cout << "RandomAccessIterator" << endl;
}

//测试程序  
int main()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    list<int> l;
    l.push_back(1);
    l.push_back(2);
    deque<int> d;
    d.push_back(1);
    d.push_back(2);
    vector<int>::iterator iter1 = v.begin();
    list<int>::iterator iter2 = l.begin();
    deque<int>::iterator iter3 = d.begin();
    MyAdvance(iter1, 1); //vector的迭代器是原生指针,因此是RandomAccessIterator  
    MyAdvance(iter2, 1); //链表的迭代器是双向的,因此是BidirectionalIterator  
    MyAdvance(iter3, 1); //双端队列支持随机读写,因此是RandomAccessIterator  

    system("pause");

    return 0;
}

本例子取自:
Effective C++书上的源码
and:
http://blog.csdn.net/wuzhekai1985/article/details/6656659
这位作者的博客(STL中的C++技术)都很不错,值得推敲!

关于C++模板技术,以及在STL的运用的技术还有很多,后续会继续更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值