STL源码剖析之traits技巧(下)

21Traits方法:可以用来萃取迭代器的特性

(接着上一篇文章说到原生指针与traits技巧的使用,这里拓展了一点其他类型的使用方法,和上一篇文章介绍的方法一样。)

Template

Struct iterator_traits //输入带有value_type的指针

{

Typedef typename I::value_type value_type;

}

Template

Typename Iterator_traits::value_type

Func(I ite)

{

Return *ite;

}

Template

Struct iterator_traits //可以输入原生指针

{

Typedef T value_type;

}

clip_image002

clip_image004

为了让这个traits可以运作,每个迭代器都必须自己定义 内嵌型别 nest typedef!!!!

clip_image006

22如果希望容器能很好的与预定义的STL交互,那么就要为 自定义的容器 的迭代器 定义下面5个内嵌类型

Template<class I> //容器对应的迭代器类型

Struct iterator_traits //非原生指针

{

Typedef typename I::iterator_category;

Typedef typename I::value_type; //获取迭代器所指的对象的类型

Typedef typename I::difference_type; //迭代器间距,容器的容量

Typedef typename I::pointer;

Typedef typename I::reference; //返回引用类型

};

Template

Typename iterator_traits::difference_type count(I first, I last, const T& value)

{

Typename iterator_traits::difference_type n=0;

For(;first!=last;++first)

If(*first ==value)

++n;

Return n;

}

//偏特化,得到“原生指针”的difference type

Template

Struct iterator_traits //

{

Typedef ptrdiff_t difference_type;

}

23

迭代器可以分为以下几大类

1 Input Iter

2 Output Iter

3 Forward Iter

4 Bidirectional Iter

5 Random Access Iter

我们一般会根据不同的iter采取不同的行为

Template

Void advance(InputIterator& I, Distance n)

{

If( is_random_access_iterator(i)) //判断迭代器的类型

Advance_RAI(I,n);

Else if(xxx)

Advance_xx(I,n);

//…..

}

这种做法只能在执行期才确定使用哪个版本(if - else ),会影响程序的效率,最好可以在编译时就选择正确的版本

怎么做到在编译器就可以正确的获取迭代器的类型,并根据类型做出不同的响应? 答案是 traits技巧

我们可以通过一个模板的形式,并利用traits萃取出迭代器的种类,利用这个迭代器相应型别作为advance的第三个参数

什么是traits?

Template

Struct iterator_traits

{

Typedef typename I::value_type value_type;

};

Trait的作用就是如果模板参数类I有自己的value type,那么通过traits,可以萃取出的value type就是I的value type,这样一来,我们在使用一个traits就可以得到这个模板参数I的value type

Template

Typename iterator_traits::value_type func(I ite)

{

Return ite; //操作会被重载

}

利用traits技法,可以在iterator上封装多一个iterator_trait,将类型信息作为其数据成员,这样一来就可以方便的获取一个模板迭代器的实际类型

我们可以通过一个模板的形式,并利用traits萃取出迭代器的种类,利用这个迭代器相应型别作为advance的第三个参数。

首先定义5个类型

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

接下来就可以为advanced函数定义重载函数,每个函数都有一个相应上面类型的参数。

Template

Inline void advance(input_iterator &I, distance n, input_iterator_tag)

{

While (n--) ++i;

}

Template

Inline void advance(RandomAccessIterator& I, distance n,random_access_iterator_tag){};

上面是两个重载的函数,和以前不同的是加入了tag类型

接下来就是一个接口来在编译期判定执行那个函数

Template

Inline void advance(InputIterator& I, distance n)

{

Advance(I, n, iterator_traits::iterator_category() );

精华就在这里,通过traits的技法,将InputIterator的实际相关信息萃取出来,作为参数处理,这样可以很好的利用上重载的好处。而且 traits还支持偏特化性质。

}

24如果模板中有一个模板参数是基类,然后没有一个模板参数是子类的重载,那么使用子类传入时,会调用基类的模板

Template

Inline iterator_traits::difference_type __distance(InputIterator first, InputIterator last, input_iterator_tag){}

Template

Inline iterator_traits::difference_type __distance(RandomAI first, RandomAI last, random_access_iterator_tag){}

Template

Inline iterator_traits::difference_type distance(InputIterator first, InputIterator last)

{

Typedef typename iterator_traits::iterator_category;

Return __distance(first, last, category() );

}

这个distance可以接收任何类型的迭代器,这里的inpputIterator是按照STL算法的命名规则,按所能接受的最初级别来命名。而如果这些迭代器有继承关系,那么在使用Out,For,Bid这3个迭代器的话会默认调用input那个类型的迭代器,这和一开始的【如果模板中有一个模板参数是基类,然后没有一个模板参数是子类的重载,那么使用子类传入时,会调用基类的模板】的说法一致

关于能提供traits的迭代器,STL提供了一个基类,让我们实现自己的迭代器。

25【24】

迭代器 需要设计适当associated type

容器 需要 设计适当迭代器

(因为只有容器才能知道如果利用迭代器来遍历自己,并执行迭代器所应该有的各种行为-如前进等)

算法 可以独立容器 和 迭代器 ,以迭代器为对外接口就可以

Traits技巧! 利用“内嵌类型template参数推导(Typedef typename I::value_type value_type;)”使得C++可以执行编译期类型识别(因为C++本身不是一门强类型的语言),这是一项很强大的技术

26STL仅仅使用traits对迭代器加以规范,制定出iterator_traits(STL),而SGI则拓展了它,实现了__type_traits 用来萃取类型(type)(SGI)的特性,如果我们可以获得某个类型的特性,例如 是有由non-trivial default constructor等等,那么我们就可以在构造,析构等操作时,选择最有效率的措施,而采用直接操作提供效率

clip_image008clip_image010

struct __true_type{};

struct __false_type{};

template

struct __type_traits

{

typedef typename T::has_trivial_default_constructor;

};

template

struct Iterator

{

typedef __true_type has_trivial_default_constructor;

};

template

typename __type_traits::has_trivial_default_constructor hasTrivialDefaultConstructor()

{}
原文链接: https://www.cnblogs.com/aga-j/archive/2011/06/05/2073041.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/26787

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月8日 上午4:24
下一篇 2023年2月8日 上午4:25

相关推荐