《STL源码剖析》traits技法

来源:互联网 发布:ios开发没有mac怎么办 编辑:程序博客网 时间:2024/05/16 17:16

包括

1】:萃取迭代器特性:iterator_traits

2】:萃取型别特性__type_traits

萃取迭代器特性    

特性萃取机

      

  

每个迭代器要融入STL大家庭,必须遵守约定,自行以内嵌型别定义的方式定义出相应型别(以上5个)

原因—作用:

因为:模板参数推导机制无法推导函数的返回值型别;

所以:使用内嵌型别声明  typedef T value_type

又因为:原生指针无法定义内嵌型别

所以:对原生指针T*,指向const的指针(常对象的指针const T *)进行模板特化

-----》模板类:struct iterator_traits专门提取迭代器的特性

用法:iterator_traits<迭代器>::5个特性之一

5个特性:

value type:迭代器指向对象的型别

difference type:2个迭代器间的距离

pointer:指向迭代器所指之物

reference:函数如果要传回左值,都以by reference的方式进行

iterator_category:迭代器的相应型别,引发大量的编程

实现:

1】

 

 2】 2个特化  原生指针,const指针

          

      

    

     

迭代器相应型别

1】input itetator:这种迭代器所指对象,不允许改变,只读

output iterator:只写

forward iterator:读写

以上三种仅支持operator++

bidirectional iterator:双向移动   支持operator++,--

random access iterator:涵盖所有指针算术能力,p+n,p-n,p[n],p1-p2,p1<p2

2】

为了编译器就选择正确的版本

所以:利用重载函数

外层函数的第三个参数:迭代器类型的相应型别(5个)

这个相应型别一定要是类class,不能是数值等,编译器依据它来进行重载决议

所以:1】定义5个类代表5中迭代器类型

                    

2】只是为了激活重载机制,根本不用使用参数

这些classes只作为标记,不需要任何成员

迭代器型别用法

方式一:参数临时对象

iterator_traits<inputiterator>::iterator_category()

方式二:

typedef typename iterator_traits<inputiterator>::iterator_category    category;

category();

方式三:

  iterator_category(迭代器)   注:iterator_category是辅助函数

例子:

1】外层函数

           

       

        

2】内层函数  函数重载

          

迭代器保证

原因:类似仿函数

为了融于整个STL框架,任何迭代器都应该提供5个内嵌相应型别,以利于traits萃取,否则无法与其他STL组件搭配。

所以:必须继承自迭代器类

   

   说明:

iterator 类不含任何成员,只是型别定义,

        所以继承它不会调用任何负担,后单个参数有默认值,故新的迭代器只需要提供前2个参数。

例子:
template<class item>
struct listiter:
        public iterator<std::forward_iterator_tag,item>
{...}

萃取型别的特性__type_traits

1】  iterator_traits---萃取迭代器的特性

__type_traits---萃取型别(type)的特性

2】如果有平凡的构造,析构,复制构造,赋值,对型别进行构造,析构,复制构造,赋值时,使用最有效率的措施直接内存处理(memmove,memcopy等),

     不用使用构造,复制构造等

3】为了针对不同的型别,完成编译期的派送,定义2class,相应真或假

原因:类似萃取迭代器特性时,定义的5个迭代器型别

希望利用相应结果(真/假)进行参数推导,而编译器只对class对象形式的参数,才做参数推导。所以定义如下2个结构体:

struct _true_type{};

struct _false_type{};

效果:空白的类没有任何成员,没有额外负担,又能够标示真假。

实现

  1】全部定义为__false_type  最保守的值

template <class type>

struct __type_traits{

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

};

2]针对内建类型的特化版本【char,unsigned char ,short,int,long,double等等】

每一个成员的值都是__true_type,表示这些型别都可以采用最快放手(如memcpy)来进行拷贝或赋值

例如:

struct __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  has_POD_type;

};

3】原生指针的偏特化

template <class T>

struct __type_traits<T*>{

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

};

例子:数组拷贝

外层函数:

     

内层函数:

     

针对自定义类

自定义类—默认为__false_type,除非明确定义

特化版本,告诉编译器以下事实:

template <>struct__type_traits<shape>{

typedef __true_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  has_POD_type;

};

 

一个类什么时候需要非平凡的构造,析构等函数?

准则:

如果class内含指针成员,并且对它进行内存动态配置,

此时:全部为__false_type—即不能采用最有效的内存操作方式,

类需要实现自己的非平凡函数。

总结

有了_type_traits,面对标量型别,便有足够的信息决定采用最有效的拷贝操作或赋值操作因为每一个标量型别都有相应的_type_traits特化版本,其中每一个typedef的值都是_true_type.



0 0
原创粉丝点击