__iterator_traits技法用于模板编程,STL所有算法都是基于模板实现的。
先看下面是一个例子:
template <class I, class T> void func_impl(I iter, T t) { // ... } template<class I> inline void func(I iter) { func_impl(iter, *iter); // ... } int main() { int i; func(&i); return 0; }
但是,想象一下,“template参数推导技术”只是推出参数,无法推导返回值,怎么办?我们可以在迭代器里内嵌一个型别声明。如下:
template<class T> struct MyIter { typedef T value_type; // .... }; template<class I> typename I::value_type func(T iter) { return *iter; }
但问题又来了,并不是所有类型都是calss type,所以无法为它定义内嵌型别,template partial specialization(模板偏特化)可以做到,但要用另一个模板作为中间层进而偏特化(这里就是__iterator_traits技法了),如下:
//__iterator_traits template<class I> struct iterator_traits { typedef typename I::value_type value_type; }; //__iterator_traits偏特化版本,准确接受内置指针类型 template<class I> struct iterator_traits<T*> { typedef T value_type; }; //接受指向const类型数据的指针 template<class I> struct iterator_traits<const T*> { typedef T value_type; };
template<class T> struct MyIter { typedef T value_type; // .... }; template<class I> typename iterator_traits<I>::value_type func(I iter) { return *iter; }
不过,在《stl源码剖析》是在2002出版的,我看了下只有第一版,那时候还没有C++11,在C++11的新语法下,我们其实可以这样解决“无法推导返回值”的问题,那就是利用auto、decltype、尾置返回语法的性质:
template<class T> struct MyIter { typedef T value_type; // .... }; template<class I> auto func(I iter) -> typename remove_reference<decltype(*iter)>::type { return *iter; }因为在推导返回值时,参数类型已有函数实参推断出来了,再用尾置返回,搞定。同时,要用decltype(*iter)得到的是引用类型,故需要remove_reference。
所以,STL里的算法模板都是这样实现,如果我们要设计与STL水乳交融的类,那就要符合STL的一些基本要求了。
1.设计类
2.设计类的迭代器
迭代器要满足STL的要求,那么你的迭代器就能用在STL算法。
STL有5中基本型别,它的特性萃取机这样定义的:
template<class I> struct iterator_traits { typedef typename I::iterator_category iterator_category; typedef typename I::value_type value_type; typedef typename I::difference_type difference_type; typedef typename I::pointer pointer; typedef typename I:;reference reference; }当然了, 还有针对pointer和pointer-to-const者设计特例化版本,这些在STL内部已经实现了, 我们需要做的是,设计一个迭代器,里面要嵌入5中型别的定义。
iterator_category有什么用?它是用来判别这个迭代器(或许是指针)是什么类型的,根据移动特性与施行操作,迭代器被分为5类:
①Iuput iterator,只读
②Output iterator,只写
③Foreard iterator,可读写
④Bidirection iterator,可双向移动
⑤Random Access iterator,前四种提供基本操作(operator++,第四种在加上operator--),这种包含所有指针算术能力(p+n,p-n,p[n],p1<p2...)
为了分别五种型别,STL内部定义了5个类来区分:
struct input_iterator_tag{}; struct output_iteraotr_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{};
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; };
template<class InputIterator, class Distance> inline void __advance(InputIterator &i, Distance n, input_iterator_tag) { while (n--)++i; } template<class ForwardIterator, class Distance> inline void __advance(ForwardIterator &i, Distance n, forward_iterator_tag) { __advance(i, n, input_iterator_tag()); } template<class BidirectionIterator, class Distance> inline void __advance(BidirectionIterator &i, Distance n, bidirectional_iterator_tag) { if (n >= 0) while(n--) ++i; else while(n++) --i; } template<class RandomAccessIterator, class Distance> inline void __advance(RandomAccessIterator &i, Distance n, random_access_iterator_tag) { i += n; } template<class Iterator, class Distance> inline void advance(Iterator &i, Distance n) { __advance(i, n, iterator_traits<Iterator>::iterator_category()); }