迭代器设计思维——STL关键所在
STL的中心思想在于:将数据容器(containters)和算法(algorithms)分开,彼此独立设计,最后再以一帖胶着剂撮合在一起。
迭代器是一种smart pointer
迭代器是一种行为类似指针的对象,而指针的各种行为中最常见也最方便的便是内容提领(dereference)和成员访问(member access),因此,迭代器最重要的编程工作就是对operator* 和operator-> 进行重载工作。
Traits编程技法——STL源代码门钥
traits,又被叫做特性萃取技术,说得简单点就是提取“被传进的对象”对应的返回类型,让同一个接口实现对应的功能。因为STL的算法和容器是分离的,两者通过迭代器链接。算法的实现并不知道自己被传进来什么。萃取器相当于在接口和实现之间加一层封装,来隐藏一些细节并协助调用合适的方法,这需要一些技巧(例如,偏特化)。
首先,在算法中运用迭代器时,很可能会用到其相应型别(迭代器所指之物的型别)。假设算法中有必要声明一个变量,以“迭代器所指对象的型别”为型别,该怎么办呢?
解决方法是:利用function template的参数推导机制。
template <class I, class T> void func_impl(I iter, T t) { T tmp; // 这里就是迭代器所指物的类型新建的对象 // ... 功能实现 } template <class I> inline void func(I iter) { func_impl(iter, *iter); // 传入iter和iter所指的值,class自动推导 } int main() { int i; func(&i); }
我们以func()对外接口,却把实际操作全部置于func_imp1()之中。由于func_imp1()是一个function template,一旦被调用,编译器会自动进行template参数推到。于是导出型别T,顺利解决问题。
迭代器相应型别不只是“迭代器所指对象的型别”一种而已。根据经验,最常用的相应型别有五种,然而并非任何情况下任何一种都可以利用上述的template参数推导机制来取得。
函数的“template参数推导机制”推导的只是参数,无法推导函数的返回值类型。万一需要推导函数的传回值,就无能为力了。
声明内嵌型别似乎是个好主意,这样我们就可以直接获取。
template <class T> struct MyIter { typedef T value_type; // 内嵌型别声明 // ... }; template <class I> typename I::value_type //这一行是func的回返值型别 func(I ite) { return *ite; } // ... MyIter<int> ite(new int(8)); cout << func(ite);
并不是所有迭代器都是class type,原生指针就不是。如果不是class type,就无法定义它内嵌型别。但STL绝对必须接受原生指针作为一种迭代器。template partial specialization 可以做到。
Partial Specialization (偏特化)意义:如果class template拥有一个以上的template参数,我们可以针对其中某个(或数个,但非全部)template参数进行特化工作。换句话说,我们可以在泛化设计中提供一个特化版本(也就是将泛化版本中的某些template参数赋予明确的指定)。
《泛型思维》对Partial Specialization 定义:针对(任何)template参数更进一步的条件限制所设计出来的一个特化版本。由此,面对以下这么一个class template:
template<typename T> class C {……}; //这个泛化版本允许(接受)T为任何型别 //我们更容易接受它有一个形如下的Partial Specialization template<typename T> class C<T*> {……}; //这个泛化版本仅适用于"T为原生指针"的情况,便是"T为任何型别"的一个更进一步的条件限制
关键地带!下面这个class template专门用来萃取迭代器的特性,而value type正是迭代器的特性之一:
template <class I> struct iterator_traits { typedef typename I::value_type value_type; }; template <class I> struct iterator_traits<T*> { typedef T value_type; }; template <class I> typename iterator_traits<I>::value_type func(I ite) { return *ite; }
func在调用 I 的时候,首先把 I 传到萃取器中,然后萃取器就匹配最适合的 value_type。(萃取器会先匹配最特别的版本)这样当你传进一个原生指针的时候,首先匹配的是带<T*>的偏特化版本,这样 value_type 就是 T,而不是没有事先声明的 I::value_type。这样返回值就可以使用 typename iterator_traits<I>::value_type
来知道返回类型。
感觉乱七八糟的,对这章的理解还不是很到位,继续往后看了。。。。