条款47:请使用traits classes表现类型信息(1)

条款47:请使用traits classes表现类型信息(1)
    Use traits classes for information about types.

    今天我们讨论的这款内容涉及到一个STL实现上的一个关键技术traits技术,简单的说就是类的型别判定技术.
由于本条款要讨论内容比较多,所以我将分成两篇文章来表述,今天我们只讨论traits classes的实现,明天我将讨
论其使用,废话我就不多说了,我们现在就开始:
    我们知道STL迭代器可分为五类,我再来简单的唠叨一下:input迭代器只能向前移动,一次一步,客户只可读取(
不能修改)它们所指的内容,而且只能读取一次;output迭代器情况类似,只是为了输出;以上这两种分别模仿文件的
读写指针,分类的代表为istream_iterators和ostream_iterators.它们两个属于能力最小的迭代器分类,只适合一
次性操作算法.第三类迭代器为forward迭代器,该种迭代器能够做上述两种类所能做的每一件事情,而且可以读写
所指物一次以上.第四类迭代器为bidirectional迭代器,比前一种威力更大,除了可以向前移动还可以向后移动.
STL的list,set,multiset,map,multimap的迭代器都是属于这一分类.最后一种分类也是威力最强的迭代器当属
random access迭代器,它可以在常量时间内向前或向后迢遥任意距离.vector,deque和string提供的迭代器就属于
这一分类.
    对于这五种分类,C++标准库提供专门的类型标记结构对它们进行区分:
    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{};
    下面我们来看STL算法里面的函数advance的实现,其作用就是将某个迭代器移动某个距离:
    template <typename IterT, typename DistT>
    void advance(IterT& iter, DistT d);
    为了对所有的迭代器分类都进行,我们最希望以下列方式进行实现:
    template <typename IterT, typename DistT>
    void advance(IterT& iter, DistT d)
    {
        if( iter is a random access iterator ){
            iter += d; //针对random access迭代器使用迭代器算术运算
        } else { //针对其它迭代器分类反复调用++或者--
            if( d >= 0 ){
                while( d-- )
                    ++iter;
            } else {
                while( d++ )
                    --iter;
            }
        }       
    }
    当写完上面的伪以后,我们就会立刻将焦点转移到一个点上:必须能够判断iter是否为random access迭代器
,也就是说需要知道类型IterT是否为random access迭代器分类.换句话说我们需要取得类型的某些信息.那就是
traits让你得以进行的事:它们允许你在编译期间取得某些类型信息.
    Traits并不是C++关键字或一个预先定义好的构件;它们是一种技术,该技术的要求之一是,它对内置类型和用
户自定义类型的表现必须一样好.这就意味着'类型内的嵌套信息'这种东西出局了,因为我们无法将信息嵌套于
原始指针内.因此类型的traits信息必须位于类型自身之外.标识程序库的做法是把它放进一个template及其一个
或多个特化版本中.这样的templates在标准程序库中有若干个,其中针对迭代器者被命名为iterator_traits:
    template<typename IterT>
    struct iterator_traits;
    iterator_traits以两个部分实现上述所言.首先它约定每一个用户自定义迭代器类型必须嵌套一个typedef,
名为iterator_category,用来确认类型信息.比如deque可随机访问,所以针对deque迭代器而设计的class看起来
会是这个样子:
    template<...>
    class deque{
    public:
        class iterator{
        public:
            typedef random_access_iterator_tag iterator_category;
            ...
        };
        ...
    };
    list迭代器可双向行进,所以应该这样:
    template<...>
    class list{
    public:
        class iterator{
        public:
            typedef bidirectional_iterator_tag iterator_category;
            ...
        };
        ...
    };
    对于iterator_traits只要响应iterator class的嵌套式typedef即可:
    template <typename IterT>
    struct iterator_traits{
        typedef typename IterT::iterator_category iterator_category;
        ...
    };
    上面的对用户自定义类型行得通,但是仅仅这样的iterator_traits是不够的,你必须还要提供对指针(也是一种
迭代器)的支持,因为指针不可能嵌套typedef.于是我们就让iterator_traits的第二部分专门对付指针,它所利用的
工具就是模板的偏特化技术.由于指针的行径与random access迭代器类似,所以iterator_traits为指针指定的迭代
器类型如下:
    template<typename IterT>
    struct iterator_traits<IterT*>{
        typedef random_access_iterator_tag iterator_category;
        ...
    };
    OK!现在你知道如何来实现一个traits class了,我们来大概简述一下如何设计并实现一个traits class:
    ■ 确认若干你希望将来可取得的类型信息.
    ■ 为该信息选一个名称(例如iterator_category)
    ■ 提供一个template和一组特化版本,内含你希望支持的类型相关信息.
    好了,今天就到此为止,明天我们继续讨论.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值