迭代器的设计思维--STL设计理念
STL在设计的时候希望达到将数据结构和算法分离开来独立设计,最后再使用一点耦合剂来使它们联系起来。
这里举了一个容器、算法、迭代器的例子,就是find函数,对于不同类型的迭代器,都可以讲其中的数据与value进行对比,其实表面上看上去迭代器是依附于容器的,那么迭代器是如何设计的呢?它的本质又是什么?
template <class InputIterator, class T>
InputIterator find(InputIterator first,InputIteratorlast,const &T value)
{
while(first != last && *first != value)
++first;
return first;
}
迭代器的本质是一种智能指针
迭代器最主要最常见的功能就是解引用和成员访问,因此迭代器最重要的编程工作就是对operator*和operator->进行重载。对于智能指针的设计可以见auto_ptr的设计等内容。
下面举List的例子,List类里面存储着一些增删改查等操作。还有就是每一个链表节点的结构ListItem
template <typename T>
class List
{
public:
void insert_front(T value);
void insert_end(T value);
void display(std::ostream &os = std::out) const;
//...
private:
ListItem<T> * __end;
ListItem<T> * __front;
//...
};
//List的节点结构
template <typename T>
class ListItem{
public:
T value();
ListItem * next();
//...
private:
T __value;
ListItem *__next;
//...
};
迭代器的设计其实和智能指针较为相像,主要是对各种运算符的重载
template <class Item>
struct ListIter
{
Item* ptr;
ListIter(Item * p = 0): str(p);
Item & operator*() const {return * ptr;}
Item & operator->() const {return * ptr;}
ListIter & operator++(){prt = ptr->next(); return *this}
bool operator==(const ListIter & i)const
{
return ptr == i.ptr;
}
//...
};
在find这类函数里面如果运用到了什么相应的运算符就需要在迭代器里面进行重载设计。但是对于迭代器来说,如果要重载运算符的话就会难以避免的需要知道相应容器里面的内容,所以对于不同的容器都会设计出不同的迭代器保证细节全部被封装起来。
迭代器的相应型别
迭代器在使用的的使用进厂遇到需要判断所指对象型别的判断问题,但是c++并没有typeof(),所以对于解决类型判断有以下几种方法。
第一种 function template的参数推导,模板函数会在编译的时候就判断出传入参数的类型,当我们不知道一个函数该需要声明什么类型的迭代器的时候。可以将这个函数放在一个模板函数里面。
缺点:只能推导参数的value type但是例如返回值等情况就不能进行判断。
第二种 声明内嵌
template <class T>
struct MyIter{
typedef T value_type;
T * ptr;
MyIter(T * p = 0) : Ptr(p){}
T& operator*() const {return *ptr };
//...
};
template <class I>
typename I::value_type func(I ie) //typename可以告诉我们后面的表示的是一个变量类型
{
return *ie;
};
但是声明内嵌有一个缺陷就是,不是所有的类型都是class type 如果不是的话就很难做到对value_type进行内部声明。
偏特化的作用
在泛化设计中提供一个特化版本,称为偏特化。举个例子
template <typename T>
class c{//...}; //这个类接受类型的T
template <typename T>
class c<T*>{}; //这个只接受原生指针
偏特化就是为了让原生指针也可以被traits出来,非常好用,为了得到相应的value_type,trait编程技法使用泛型编程的变量类型自动推导的功能。为了使trait更好用,还是用了偏特化使得原生指针也可以被提取出来,以上就是实现traits的一个思路的演变过程