《C++11/14高级编程:Boost程序库探秘》笔记
迭代器模式
”提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示“
C++标准(C++11.24.2)将迭代器分为五类:输入迭代器(只读迭代器)、输出迭代器(只写迭代器)、前向迭代器(可以读写,提供operator++,可以执行相等比较和赋值操作)、双向迭代器(在前向基础上增加了operator- -)、随机访问迭代器(在双向基础上增加了迭代器的算术运算功能,提供operator[]和operator+=)。
iterators库定义了一组基于标准库的新的迭代器概念、构造框架和有用的适配器。首先,区分了迭代器的值访问概念和遍历概念,重新划分了迭代器的类型。
根据值访问方式,迭代器分为四类:
- 可读迭代器:提供operator*,可返回可转换为类型T的右值。
- 可写迭代器:提供operator*,可以执行赋值操作(不一定是左值)。
- 可交换迭代器:两个迭代器所指的值可用标准库的iter_swap()函数交换,即同时满足可读和可写的要求。
- 左值迭代器:满足可交换迭代器,并且operator*可返回左值,即类型T的引用。
根据遍历方式,迭代器分五类:
- 可递增迭代器:提供operator++,可拷贝构造和赋值
- 单遍迭代器:增加operator==、operator!=比较操作
- 前向遍历迭代器:增加difference_type类型定义,可计算距离和缺省构造
- 双向遍历迭代器:增加operator- -,可以逆向遍历
- 随机访问遍历迭代器:增加迭代器的算术运算和比较运算,并提供operator[]。
标准库提供了三个迭代器辅助函数(C++11.24.4.4)
- advance(pos,n):使迭代器前进或后退n个位置
- distance(p1,p2):计算两个迭代器间的距离
- iter_swap():交换两个迭代器所指的元素的值
这三个辅助函数能够以统一的方式操作迭代器,无须关心迭代器的类别。
标准库提供了一些迭代器适配器,可以把一种迭代器转换为另一种迭代器(C++11.24.5)
- 逆向迭代器:适配后迭代器可以逆序迭代
- 转移迭代器:C++11/14新增的迭代器适配器,迭代器返回右值引用
- 插入迭代器:把赋值操作转换为执行插入操作的输出迭代器
- 流迭代器:把IO流转换为迭代器操作
next_prior
next_prior组件提供了两个非常简单易用的模板函数next()和prior(),使用了迭代器辅助工具advance()为仅提供operator++和operator–的迭代器增加了前向或后向N步的通用解法,其实就是用封装了一层advance()。
template<class T>
inline T next(T x) //单参形式
{
return ++x;
}
template<class T,class Distance>
inline T next(T x, Distance n) //双参形式
{
std::advance(x, n);
return x;
}
template<class T>
inline T prior(T x) //单参形式
{
return --x;
}
template<class T, class Distance>
inline T prior(T x, Distance n) //双参形式
{
std::advance(x, -n);
return x;
}
advance()会自动根据迭代器的类型采取最有效率的步进措施——对于随机访问迭代器直接调用operator+=,对于其他的迭代器则循环调用递增或递减操作。
如果迭代器不提供operator++或operator- -,那么使用这两个函数会引发编译错误。
虽然这两个名字叫next和prior,但是双参版本的第二个参数可以传入负数,也就是实际上可以使迭代器任意前后移动(前提是迭代器支持operator- -)
这个组件位于名字空间boost,需要包含头文件<boost/next_prior.hpp>,即:
#include <boost/next_prior.hpp>
using namespace boost;
C++11标准在头文件<iterator>里定义了std::next()和std::prev(),实现的功能相同,但声明形式略有不同:
template<class ForwardIterator>
ForwardIterator next(ForwardIterator x,difference_type n = 1); //带缺省参数
template<class BidirectionalIterator>
BidirectionalIterator prev(BidirectionalIterator x,difference_type n = 1); //带缺省参数
iterator_traits
标准库的std::iterator_traits接受一个迭代器(或指针)类型,可以获得迭代器(或指针)所必备的五个类型信息:iterator_category(迭代器的分类)、value_type(迭代器所指的值类型)、reference(迭代器的值引用类型)、pointer(迭代器的指针类型)、difference_type(迭代器的距离类型),但是标准中把这五个类型揉成一团,从模板元编程的角度看不符合元函数的规范定义,是非标准元函数。
iterator_traits库把std::iterator_traits中揉成一团的元数据分解开来,形成了五个标准元函数,功能是完全相同的。
- iterator_category<I> :返回迭代器的分类
- iterator_value<I> :返回迭代器的值类型
- iterator_reference<I> :返回迭代器的值引用类型
- iterator_pointer<I> :返回迭代器的指针类型
- iterator_difference<I> :返回迭代器的距离类型
这五个元函数其实也是调用了标准的iterator_traits:
template<class Iterator>
struct iterator_value
{
typedef typename iterator_traits<Iterator>::value_type type;
};
这个库位于名字空间boost,需要包含头文件<boost/iterator/iterator_traits.hpp>
iterator_facade
iterator_facade是一个重要组件,它使用外观模式提供一个辅助类,能够容易地创建符合标准的迭代器。iterator_facade定义了数个迭代器的核心接口,用户只需实现这些核心功能就可以编写正确且完备的迭代器。
iterator_facade要求用户的迭代器类必须实现下面五个功能(共六个接口,但依据迭代器的类型某些函数不实现)。
- 解引用:deference(),实现可读迭代器和可写迭代器必需
- 相等比较:equal(),实现单遍迭代器必需
- 递增:increment(),实现可递增迭代器和前向遍历迭代器必需
- 递减:decrement(),实现双向遍历迭代器必需
- 距离计算:advance()和distance_to(),实现随机访问遍历迭代器必需
这些核心操作将被iterator_facade用来实现迭代器的外部接口,所以通常它们都是private的。
为了使iterator_facade访问这些核心操作函数,库又提供了一个辅助类boost::iterator_core_access,它定义了可以访问private核心操作的若干静态成员函数,用户迭代器要把它声明为友元。
iterator_facade基于迭代器核心操作实现迭代器功能,类摘要如下:
template<
class Derived, //子类的名字,用户正在编写的自己的迭代器
class Value, //迭代器的值类型
class CategoryOrTraversal, //迭代器的分类
class Reference = Value&,
class Difference = ptrdiff_t,
>
class iterator_facade
{
public:
//迭代器各种必需的类型定义
typedef remove_const<Value>::type value_type;
typedef Reference reference;
typedef Value* pointer;
typedef Difference difference_type;
typedef some_define iterator_category;
//迭代器的各种操作定义
Reference operator*() const;
some_define operator->() const;
some_define operator[](difference_type n) const;
Derived& operator++();
Derived operator++(int);
Derived& operator--();
Derived operator--(int);
Derived& operator+=(difference_type n);
Derived& operator-=(difference_type n);
Derived operator-(difference_type n) const;
};
示例一
编写一个可写单遍迭代器
template<typename T>
class vs_iterator :
public boost::iterator_facade< //基类链技术继承
vs_iterator<T>, T, //子类名和值类型
boost::single_pass_traversal_tag> //单遍迭代器类型
{
private:
std::vector<T>& v; //容器的引用
size_t current_pos; //迭代器的当前位置
public:
typedef boost::iterator_facade<vs_iterator<T>, T,boost::single_pass_traversal_tag> super_type;
typedef vs_iterator this_type; //定义自身的别名
typedef typename super_type::reference reference; //使用基类的引用类型
vs_iterator(std::vector<T> &_v,size_t pos = 0) :
v(_v), current_pos(pos)
{}
vs_iterator(this_type const& other) :
v(other.v), current_pos(other.current_pos)
{}
void operator=(this_type const& other)
{
this->v = other.v;
this->current_pos = other.current_pos;
}
private:
friend class boost::iterator_core_access; //必需的友元声明
reference dereference() const //解引用操作
{
return v[current_pos];
}
void increment() //递增操作
{
++current_pos;
}
bool equal(this_type const& other) const //比较操作
{
return this->current_pos == other.current_pos;
}
};
int main()
{
std::vector<int> v{ 1,2,3,4,5 };
vs_iterator<int> vsi(v), vsi_end(v, v.size());
*vsi = 9;
std::copy(vsi, vsi_end, std::ostream_iterator<int>(std::cout, ","));
return 0;
}
示例二
定义一个每次跳跃式前进N个位置的步进迭代器step_iterator:
template<typename T,std::ptrdiff_t N = 2> //缺省一次前进两步
class step_iterator :
public boost::iterator_facade< //基类链技术继承
step_iterator<T>, //子类名
typename boost::iterator_value<T>::type const, //元函数获得值类型
boost::single_pass_traversal_tag> //单遍迭代器类型
{
private:
T m_iter; //迭代器位置
public:
typedef boost::iterator_facade<step_iterator<T>, typename boost::iterator_value<T>::type const, boost::single_pass_traversal_tag> super_type;
typedef step_iterator this_type; //定义自身的别名
using typename super_type::reference; //使用基类的引用类型
step_iterator(T x) :m_iter(x) {}
step_iterator(this_type const& other) = default; //拷贝构造,使用default
this_type& operator=(this_type const& other) = default; //赋值函数
private:
friend class boost::iterator_core_access; //必需的友元声明
reference dereference() const //解引用操作
{
return *m_iter;
}
void increment() //递增操作
{
std::advance(m_iter,N);
}
bool equal(this_type const& other) const //比较操作
{
return m_iter == other.m_iter;
}
};
int main()
{
char s[] = "12345678";
std::copy(s, s + 8, std::ostream_iterator<char>(std::cout));
step_iterator<char*> first(s), last(s + 8); //用char*迭代,默认步长2
std::copy(first, last, std::ostream_iterator<char>(std::cout));
return 0;
}
iterator_adaptor
iterator_adaptor基于对象适配器模式,主要功能就是把已经存在的类型适配为一个新的迭代器。
iterator_adaptor派生自iterator_facade,同样使用了基类链技术,类摘要如下:
template<
class Derived, //迭代器子类名
class Adaptee, //被适配的迭代器
class Value = use_default, //值类型
class CategoryOrTraversal = use_default, //迭代器分类标志
class Reference = use_default, //迭代器值引用类型
class Difference = use_default, //迭代器距离类型
>
class iterator_adaptor : public iterator_facade<Derived, ...>
{
friend class iterator_core_access; //必需的友元声明
public:
iterator_adaptor();
explicit iterator_adaptor(Adaptee const& iter);
typedef Adaptee base_type; //被适配的原始迭代器类型定义
Adaptee const& base() const;
private:
//适配Adaptee实现iterator_facade必需的六个核心迭代器接口
reference dereference() const;
bool equal(iterator_adaptor const& x) const;
void increment();
void decrement();
void advance(typename difference_type n);
difference_type distance_to(iterator_adaptor const& y) const;
protected:
typedef some_define iterator_adaptor_; //自身的类型定义
Adaptee const& base_reference() const;
Adaptee base_reference();
private:
Adaptee m_iterator; //迭代器成员变量
};
iterator_adaptor有六个模板参数,常用的是前两个,第一个Derived的含义同iterator_facade,也是自定义的迭代器类型,即子类;第二个Adaptee是要被适配的,已经存在的类型(可以是已经存在的迭代器,或者是任何其他类型),其他模板参数可以使用缺省值boost::use_default在编译期自动推导。
iterator_adaptor是对iterator_facade的一个具体实现,因此需要使用iterator_core_access作为友元,并借用Adaptee实现dereference()、increment()等六个核心操作。
iterator_adaptor的有参构造函数要求传入被适配的Adaptee实例,被保存在成员变量m_iterator。为了方便子类使用,base_reference()和base()可以直接获得被适配的原始迭代器对象m_iterator。
iterator_adaptor还有一个类型定义iterator_adaptor_,它是iterator_adaptor<Derived,…>自身,为了便于子类引用而不必写出一串的模板参数列表,子类代码可以直接使用。
示例一
把普通数组指针适配为迭代器接口,指针本身已经具有迭代器的操作,所以适配代码比较简单:
template<typename P> //适配任意的指针类型
class array_iter :
public boost::iterator_adaptor<array_iter<P>, P> //适配类型P
{
BOOST_STATIC_ASSERT(is_pointer<P>::value); //静态断言保证P必须是指针
public:
typedef typename array_iter::iterator_adaptor_ super_type; //基类定义
array_iter(P x) :super_type(x)
{}
};
int main()
{
int a[10] = { 1,2,3 };
array_iter<int*> start(a), finish(a + 10); //两个起点和终点迭代器
start += 1;
std::copy(start, finish,
std::ostream_iterator<int>(std::cout, ","));
return 0;
}
示例二
实现一个delta_iterator,可以访问存储增量数值的容器,类似标准算法partial_sum:
template<typename I>
class delta_iterator :public boost::iterator_adaptor<
delta_iterator<I>, I,
typename std::iterator_traits<I>::value_type, //值类型
boost::single_pass_traversal_tag //单向遍历标志
typename std::iterator_traits<I>::value_type const> //只读迭代器
{
private:
friend class boost::iterator_core_access;
typedef delta_iterator this_type;
typedef typename this_type::iterator_adaptor_ super_type;
typename super_type::value_type m_value; //存储当前的值
public:
explicit delta_iterator(const I& iter) :
super_type(iter), m_value(0)
{}
private:
using super_type::base;
using super_type::base_reference;
typename super_type::reference dereference() const
{
return m_value + *base(); //当前值+增量
}
void increment()
{
m_value += *base(); //计算当前值
++base_reference(); //迭代器前进
}
};
int main()
{
std::vector<int> a = { 1,2,3 }; //存储增量值,实际的数值是1,3,6
typedef delta_iterator<decltype(a.cbegin())> delta_iter;
delta_iter start(a.begin()), finish(a.end());
return 0;
}
迭代器工具
前面提到的iterator_facade和iterator_adaptor都是两个辅助类,iterators库在这两个辅助类下,实现了很多非常有用的迭代器工具,这些工具大部分位于<boost/iterator/>目录,少量位于<boost/>目录,并且都提供形如make_xxx_iterator()的工厂函数以方便使用。
1.共享容器迭代器
shared_container_iterator把一个被boost::shared_ptr管理的容器适配成迭代器的形式来操作,比直接用shared_ptr更加简单方便。
它本身几乎没有什么功能代码,仅仅是一个简单的适配,构造函数要求传入容器的迭代器和指向容器的共享指针(不是std::shared_ptr)
template <typename Container>
class shared_container_iterator :
public boost::iterator_adpator<shared_container_iterator<Container>,
typename Container::iterator> //被适配的容器迭代器
{
typedef typename Container::iterator iterator_t;
typedef boost::shared_ptr<Container> container_ref_t;
container_ref_t container_ref;
public:
shared_container_iterator() {}
shared_container_iterator(iterator_t const& x, container_ref_t const& c) :
super_t(x), container_ref(c) {}
};
//用法
auto sv = boost::make_shared<vector<int> >(10); //共享容器
typedef shared_container_iterator<vector<int>> sci_t;
sci_t first(sv->begin(),sv);
sci_t last(sv->end(),sv);
std::fill(first,last,9);
为了方便使用,shared_container_iterator还提供了一个辅助函数make_shared_container_iterator(),可以直接产生shared_container_iterator:
make_shared_container_iterator(iter,container);
省去写出临时变量,简化代码
std::fill(
make_shared_container_iterator(sv->begin(),sv),
make_shared_container_iterator(sv->end(),sv),9);
另外一个辅助函数make_shared_container_range()以pair的形式返回共享容器的两个端点,符合boost.range的概念,可以传递给使用range概念的算法
2.发生器迭代器
generator_iterator可以把一个函数或者函数对象适配成输入迭代器,每次调用operator++并解引用迭代器都会获得一个值。
generator_iterator构造函数要求传入一个发生器指针:
template<class Generator>
class generator_iterator
:public boost::iterator_facade<
generator_iterator<Generator>,
typename Generator::result_type,
boost::single_pass_traversal_tag,
typename Generator::result_type const&
>
{
public:
generator_iterator() {}
generator_iterator(Generator* g) :
m_g(g), m_value((*m_g)()) {}
void increment()
{
m_value = (*m_g)();
}
const typename Generator::result_type& dereference() const
{
return m_value;
}
bool equal(generator_iterator const& y) const
{
return this->m_g == y.m_g && this->m_value == y.m_value;
}
private:
Generator* m_g;
typename Generator::result_type m_value;
};
generator_iterator提供一个辅助函数make_generator_iterator()用于直接创建发生器迭代器,它的接口和generator_iterator的构造函数不同,不是指针而是引用:
template<class Generator>
inline generator_iterator<Generator>
make_generator_iterator(Generator& gen);
使用generator_iterator把随机数发生器适配成迭代器的形式
boost::rand48 rng;
auto iter = make_generator_iterator(rng);
for(int i = 0;i < 5; ++i)
{
cout << *++iter << ",";
}
3.逆向迭代器
reverse_iterator把一个迭代器适配成可以逆序遍历的逆向迭代器。
reverse_iterator要求适配的迭代器必须满足双向迭代器的概念,即提供operator–。
template<class Iterator>
class reverse_iterator
:public boost::iterator_adaptor<reverse_iterator<Iterator>, Iterator>
{
public:
reverse_iterator() {}
explicit reverse_iterator(Iterator x)
:super_t(x) {}
private:
typename super_t::reference dereference() const
{
return *boost::prior(this->base());
}
void increment() { --this->base_reference(); }
void decrement() { ++this->base_reference(); }
void advance(typename super_t::difference_type n)
{
this->base_reference() += -n;
}
};
reverse_iterator也提供一个辅助函数make_reverse_iterator(),可以轻松创建逆向迭代器:
char s[] = "hello iterator.";
std::copy(
make_reverse_iterator(s + std::char_traits<char>::length(s)),
make_reverse_iterator(s),
std::ostream_iterator<char>(std::cout));
4.间接迭代器
indirect_iterator把一个迭代器进行适配,在执行operator*时再多执行一次解引用操作(即再执行一次operator*),适合用于查看保存指针、只能指针或者迭代器的容器。
它的类摘要没有什么特别的,直接看看用法。
同样提供工厂函数make_indirector_iterator()
std::vector<int*> v = { new int(1),new int(2) };
//不适用间接迭代器访问元素
for (auto pos = v.begin(); pos != v.end(); ++pos)
{
std::cout << **pos << ",";
}
//使用间接迭代器访问元素
auto start = make_indirect_iterator(v.begin());
auto finish = make_indirect_iterator(v.end());
for (; start != finish;)
{
std::cout << *start++ << ",";
}
//需要及时删除指针避免内存泄露
for_each(v.begin(), v.end(), checked_deleter<int>());
5.计数迭代器
counting_iterator把一个可递增的类型适配成迭代器,使用了元编程来计算迭代器类型等模板参数
template<
class Incrementable, //可递增类型
class CategoryOrTraversal = use_default,
class Difference = use_default>
class counting_iterator :
public boost::iterator_adaptor<
counting_iterator<...> //计数迭代器自身
, Incrementable //被适配的可递增类型
, Incrementable const //值类型
, traversal //迭代器分类
, Incrementable const& //值引用类型
, difference > //迭代器距离类型
{
public:
counting_iterator();
counting_iterator(counting_iterator const& rhs);
explicit counting_iterator(Incrementable x);
reference operator*() const;
counting_iterator& operator++();
counting_iterator& operator--();
};
counting_iterator最重要的模板参数是Incrementable,它要求是可拷贝构造和可赋值的。Incrementable必须能够执行operator++操作,如果counting_iterator是单遍迭代器、双向遍历迭代器或者随机访问遍历迭代器,则Incrementable还应具备operator==、operator–和算术运算的功能。通常Incrementable是整数,但也可以是任何符合以上要求的类型(例如迭代器)。
counting_iterator可以为一个类型增加解引用操作,把它变得像一个迭代器,对于某些需要连续增加的类型来说很有用。同样,counting_iterator提供了工厂函数make_counting_iterator()
counting_iterator<int> i(100); //把int适配成计数迭代器
assert(*i++ == 100);
assert(*i == 101);
assert(*++i == 102);
std::vector<int> v;
std::copy(
make_counting_iterator(0), //从0填充到9
make_counting_iterator(10),
std::back_inserter(v)
);
把随机数发生器包装成一个可递增的类型rand_int,符合counting_iterator对Incrementable的要求:可递增、可拷贝构造、可赋值、可比较:
template<typename R>
class rand_int
{
private:
R &r; //随机数的引用
int count; //个数统计,用于相等比较
public:
rand_int(R& _r, int c = 0) :
r(_r), count(c) {}
rand_int(rand_int const& other) = default;
rand_int& operator=(rand_int const &other) = default;
void operator++()
{
++count;
}
friend bool operator==(rand_int const& l, rand_int const& r)
{
return l.count == r.count;
}
//转型到整数的操作符,返回随机数
operator typename R::result_type() const
{ return r(); }
};
int main()
{
typedef counting_iterator<rand_int<boost::rand48>, //定义为单遍迭代器
boost::single_pass_traversal_tag, int> RandIter;
boost::rand48 r; //一个随机数发生器
rand_int<boost::rand48> r1(r, 0), r2(r, 10); //包装为可递增类型
RandIter first(r1), last(r2);
std::vector<int> v;
std::copy(first, last, std::back_inserter(v));
assert(v.size() == 10);
return 0;
}
6.函数输入迭代器
function_input_iterator很类似generator_iterator,同样能够把一个函数或者函数对象适配成输入迭代器,不同的是可以使用一个状态参数设定迭代器的起点和终点(有界)。
function_input_iterator使用模板元编程技术,利用boost.function_types库提取模板参数Function的类型信息,再使用mpl模板元编程技术进行分支决策,在编译期决定从哪个基类继承,它本身并没有实际的功能。
template<class Function,class Input>
class function_input_iterator
:public mpl::if_<
function_types::is_function_pointer<Function>,
impl::function_pointer_input_iterator<Function, Input>,
typename mpl::if_<
function_types::is_function_reference<Function>,
impl::function_reference_input_iterator<Function, Input>,
impl::function_input_iterator<Function, Input>
>::type
>::type
{
typedef some_define base_type;
public:
function_input_iterator(Function& f, Input i)
:base_type(f, i) {}
};
function_input_iterator在名字空间boost::impl里面定义了三个具体实现类,分别对应函数指针、函数引用和函数对象三种情形。
由function_input_iterator的类摘要,可以看出function_input_iterator有两个模板参数,第一个Function与发生器迭代器一样,是一个具有operator()的可调用物,被用来产生迭代器的解引用值,第二个Input要求是一个可递增、可比较、可缺省构造和拷贝构造的类型,也就是支持operator++和operator==。
用起来很像发生器迭代器和计数迭代器的混合体,一方面它把函数或者函数对象适配为一个迭代器,另一方面又能够使用额外的state参数进行技术,在到达终点时自动停止。
同样提供了工厂函数make_function_input_iterator(),不过它有两种重载,分别针对函数指针和函数引用
using namespace std;
using namespace boost;
rand48 rng; //rand48随机数发生器
std::copy(
make_function_input_iterator(rng, 0), //从0开始
make_function_input_iterator(rng, 5), //到5结束
ostream_iterator<int>(std::cout, "\n") //标准流输出5个随机数
);
对比发生器迭代器的示例代码,这里可以自行控制迭代器的起点和终点,所以可以使用std::copy算法。
状态参数还可以是别的可递增可比较类型:
vector<int> v(10);
std::copy(
make_function_input_iterator(rng,v.begin()),
make_function_input_iterator(rng,v.end()),
v.begin() );
function_input_iterator还提供了一个特别的状态类型infinite,它永远不会到达终点:
struct infinite
{
infinite& operator++() { return *this; }
infinite& operator++(int) { return *this; }
bool operator==(infinite&) const { return false; }
bool operator==(infinite const&) const { return false; }
};
7.函数输出迭代器
function_output_iterator可以把一个单参函数或函数对象适配成一个标准的输出迭代器,它比较特别,没有使用iterator_adaptor或iterator_facade
template<class UnaryFunction>
class function_output_iterator
{
public:
typedef std::output_iterator_tag iterator_category; //输出迭代器分类
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
explicit function_output_iterator();
explicit function_output_iterator(const UnaryFunction& f);
output_proxy operator*(); //解引用操作
function_output_iterator& operator++();
private:
UnaryFunction m_f; //函数对象
};
解引用操作返回一个代理对象,把赋值操作转化为对函数的调用,因此*iter = t相当于m_f(t)。
用法
使用function_output_iterator配合标准算法std::copy,可以很容易地操作存储在容器中的所有元素,只需要把操作函数适配成迭代器。
示例一段代码定义一个转换ASCII码到十六进制数的函数对象to_hex,它逐个地接受字符,再转换成十六进制数存储在一个外部的vector中。
class to_hex
{
private:
std::vector<unsigned char> &v; //存储十六进制数的容器
int count; //字符计数
char trans(const char c)const //从ASCII码转换到十六进制数
{
if (c >= 'a') { return c - 'a' + 10; }
else if (c >= 'A') { return c - 'A' + 10; }
else { return c - '0'; }
}
public:
to_hex(std::vector<unsigned char> &_v) :
v(_v), count(0) {}
void operator()(const char c)
{
static char tmp;
if ((count++) % 2 == 0)
{
tmp = trans(c) * 0x10;
}
else
{
tmp += trans(c);
v.push_back(tmp);
}
}
};
int main()
{
char s[] = "1234abcd";
std::vector<unsigned char> v;
std::copy(s, s + 8,
make_function_output_iterator(to_hex(v)));
return 0;
}
8.过滤迭代器
filter_iterator可以选择性地迭代序列,筛选出所需的元素,用一个谓词(返回bool值的函数或函数对象)决定选择。
template<class Predicate,class Iterator>
class filter_iterator :
public iterator_adaptor<...>
{
public:
filter_iterator();
filter_iterator(Predicate f, Iterator x, Iterator end = Iterator());
filter_iterator(Iterator x, Iterator end = Iterator());
Predicate predicate() const;
Iterator end() const;
Iterator const& base() const;
reference operator*()const;
filter_iterator& operator++();
private:
Predicate m_pred; //谓词
Iterator m_iter; //迭代器
Iterator m_end; //迭代器终点
};
filter_iterator需要两个模板参数,第一个Predicate是过滤条件谓词,用于过滤元素,只有满足条件Predicate(x)==true才会被选择,第二个Iterator是被适配的迭代器类型,应该满足可读和单遍迭代器概念。
用法
示范使用filter_iterator来迭代筛选某个整数区间的质数。
//定义谓词函数
bool is_prime(int x)
{
for (int i = 2; i < x / 2; ++i)
{
if (x%i == 0)
return false;
}
return true;
}
int main()
{
//假设筛选10~100区间的整数,考虑使用counting_iterator来计数生成这些整数
//所有的偶数都不是质数,所以使用step_iterator跳过所有的偶数
typedef counting_iterator<int> ci_t;
ci_t c1(11), c2(101);
typedef step_iterator<ci_t> si_t;
si_t si1(c1), si2(c2);
std::copy(
make_filter_iterator(&is_prime, si1, si2), //迭代器起点,si2防止迭代越界
make_filter_iterator(&is_prime, si2, si2), //迭代器终点,si2防止迭代越界
std::ostream_iterator<int>(std::cout, " ")
);
return 0;
}
9.转换迭代器
transform_iterator把一个单参函数或函数对象应用于迭代的序列,解引用时使用函数来操作序列中的元素,效果与标准库的transform或for_each算法类似。
template<class UnaryFunction, //单参函数对象
class Iterator, //被适配的迭代器
class Reference = use_default,
class Value = use_default>
class transform_iterator :
public iterator_adaptor<...>
{
public:
transform_iterator();
transform_iterator(Iterator const& x, UnaryFunction f);
UnaryFunction functor() const;
Iterator const& base() const;
reference operator*() const;
transform_iterator& operator++();
transform_iterator& operator--();
private:
UnaryFunction m_f;
};
transform_iterator需要两个基本的模板参数,UnaryFunction是一个单参的可调用物,第二个Iterator要求满足可读迭代器概念。
transform_iterator的核心是operator*(),它变动了operator*所需的deference()成员函数,解引用原迭代器再调用UnaryFunction操作,相当于m_f(*this->base()),然后返回函数对象的转换结果(返回值)
typedef counting_iterator<int> ci_t; //使用计数迭代器向容器填充10个整数
std::vector<int> v;
std::copy(ci_t(0), ci_t(10), std::back_inserter(v));
auto f = bind(plus<int>(), _1, 5); //使用bind创建函数对象,把整数加5
std::copy(
make_transform_iterator(v.begin(), f),
make_transform_iterator(v.end(), f),
std::ostream_iterator<int>(std::cout, " ")
);
10.索引迭代器
permutation_iterator改变原有序列的索引顺序从而变动迭代顺序。
template< class ElementIterator, class IndexIterator>
class permutation_iterator
: public iterator_adaptor<
permutation_iterator<ElementIterator, IndexIterator>
, IndexIterator, typename boost::detail::iterator_traits<ElementIterator>::value_type
, use_default, typename boost::detail::iterator_traits<ElementIterator>::reference>
{
typedef iterator_adaptor<
permutation_iterator<ElementIterator, IndexIterator>
, IndexIterator, typename boost::detail::iterator_traits<ElementIterator>::value_type
, use_default, typename boost::detail::iterator_traits<ElementIterator>::reference> super_t;
friend class iterator_core_access;
public:
permutation_iterator() : m_elt_iter() {}
explicit permutation_iterator(ElementIterator x, IndexIterator y)
: super_t(y), m_elt_iter(x) {}
template<class OtherElementIterator, class OtherIndexIterator>
permutation_iterator(
permutation_iterator<OtherElementIterator, OtherIndexIterator> const& r
, typename enable_if_convertible<OtherElementIterator, ElementIterator>::type* = 0
, typename enable_if_convertible<OtherIndexIterator, IndexIterator>::type* = 0
)
: super_t(r.base()), m_elt_iter(r.m_elt_iter)
{}
private:
typename super_t::reference dereference() const
{ return *(m_elt_iter + *this->base()); }
ElementIterator m_elt_iter;
};
IndexIterator为ElementIterator定义了一个区间,区间大小不一定与原序列相同,可以是一个子区间,区间中元素也可以重复
char s[] = "abcdefg"; //元素序列
int idx[] = { 6,0,2,2,4 }; //索引序列
std::copy(
make_permutation_iterator(s, idx),
make_permutation_iterator(s, idx + 5),
std::ostream_iterator<char>(std::cout, " ")
);
//g a c c e
11.组合迭代器
zip_iterator使用tuple对多个迭代器”打包“,可以同时移动所有被打包的迭代器,解引用zip_iterator将返回持有多个迭代器解引用结果的tuple。
template<typename IteratorTuple>
class zip_iterator :
public iterator_facade<...>
{
public:
zip_iterator();
zip_iterator(IteratorTuple iterator_tuple);
const IteratorTuple& get_iterator_tuple() const;
reference operator*() const;
zip_iterator& operator++();
zip_iterator& operator--();
private:
IteratorTuple m_iterator_tuple;
};
zip_iterator只有一个模板参数,它是一个迭代器引用类型的tuple,可以包含多个迭代器,这些迭代器都应该满足可读迭代器概念,zip_iterator的operator*()将返回IteratorTuple中的迭代器各自解引用后的tuple。
用zip_iterator来实现由ASCII码转换到十六进制数的功能
class to_hex2
{
private:
std::vector<unsigned char> &v;
char trans(const char c)const //从ASCII码转换到十六进制数
{
if (c >= 'a') { return c - 'a' + 10; }
else if (c >= 'A') { return c - 'A' + 10; }
else { return c - '0'; }
}
public:
to_hex2(std::vector<unsigned char> &_v) :v(_v) {}
typedef boost::tuple<const char&, const char&> Tuple;
void operator()(Tuple const& t)const
{
static char tmp;
tmp = trans(get<0>(t)) * 0x10;
tmp += trans(get<1>(t));
v.push_back(tmp);
}
};
int main()
{
char s[] = "1234aBcD"; //base16编码字符串
std::vector<unsigned char> v;
typedef step_iterator<const char*> si_t;
std::for_each(
make_zip_iterator(boost::make_tuple(si_t(s), si_t(s + 1))),
make_zip_iterator(boost::make_tuple(si_t(s + 8), si_t(s + 9))),
to_hex2(v)
);
assert(v.size() == 4);
return 0;
}