此次将通过一个例子来说明迭代器配接器的作用,具体来说,使用迭代器配解器也可以扩展泛型算法的通用性
迭代器配接器,就是把迭代器作为参数并转化为其他迭代器的模板
现在假设我们需要从尾到头找出第一个元素值为x的元素,我们需要重新写一个泛型算法么?
总结:泛型算法不仅能实现独立于类型,独立于数据结构,还能实现普遍的抽象,甚至两个步骤看起来截然相反的场合,通过迭代器配接器也可以实现算法的统一。
迭代器配接器,就是把迭代器作为参数并转化为其他迭代器的模板
口头的空谈太过于抽象而言而无实,讲很多也未必能理解,软件工程师看代码的能力一般比看中文的能力强,通过阅读代码进行理解可靠得多,所以应该避免过多的口舌
我们的作为示范的泛型算法模板如下
template <class T, class X>
T find(T start, T beyond, const X& x)
{
while(start != beyond && *start != x)
++start;
return start;
}
显然这个算法模板是从头往后找出第一个值为x的元素,并返回这个元素对应的迭代器
现在假设我们需要从尾到头找出第一个元素值为x的元素,我们需要重新写一个泛型算法么?
答案是不需要,我们可以通过迭代器配接器来让find算法也适用于从尾到头查找元素的场合,显然这能让find算法模板的通用性进一步提高
示范代码如下:
#include <iostream>
using namespace std;
template <class T, class X>
T find(T start, T beyond, const X& x) //泛型算法模板
{
while(start != beyond && *start != x)
++start;
return start;
}
template<class It, class T>
class Rev //迭代器配解器
{
// It it; //这三行代码必须注释掉才能够编译不出错,vs编译器对模板的支持确实不行
//friend bool operator==(const Rev<It,T>&, const Rev<It,T>&);
//friend bool operator!=(const Rev<It,T>&, const Rev<It,T>&);
public:
It it; //it本应该设置成为私有成员的,为了通过vs编译器而不得以将其设为公有
Rev();
Rev(It i) :it(i) {}
operator It() { return it; }
//将参数迭代器反向
Rev<It,T>& operator++() { --it; return *this; }
Rev<It,T>& operator++(int)
{
Rev<It,T> r = *this;
--it;
return r;
}
Rev<It,T>& operator--() { ++it; return *this; }
Rev<It,T>& operator--(int)
{
Rev<It,T>& r = *this;
++it;
return r;
}
T& operator*()
{
It i = it;
--i;
return *i;
}
};
template<class It, class T>
bool operator==(const Rev<It,T>& x, const Rev<It,T>& y)
{
return x.it == y.it;
}
template<class It, class T>
bool operator!=(const Rev<It,T>& x, const Rev<It,T>& y)
{
return x.it != y.it;
}
typedef Rev<int*,int> REV;
void main()
{
int a[] = {0,7,2,3,4,5,6,7,8,9};
int *p = find(a, a+10, 8); //正向查找
cout << *p << endl;
REV r = find(REV(a+10), REV(a), 7); //反向查找
cout << *r << endl;
r--;
cout << *r; //如果输出8,则确实是反向查找元素
}
总结:泛型算法不仅能实现独立于类型,独立于数据结构,还能实现普遍的抽象,甚至两个步骤看起来截然相反的场合,通过迭代器配接器也可以实现算法的统一。
思考:执着于这种技巧是否有必要?是不是华而不实?学习究竟应该应该遵从一个什么样的原则?
大牛或前辈要是路过看到这些,请留言指点下。