boost库区间range基本原理及使用实例
由 www.169it.com 搜集整理
区间的概念类似于STL中的容器概念。一个区间提供了可以访问半开放区间[first,one_past_last)中元素的迭代器,还提供了区间中的元素数量的信息。
引入区间概念的目的在于:有很多类似于容器的类型,以及用于这些类型的简化算法。
实例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
void test_range_construct_string() { typedef std::string::iterator iterator; typedef std::string::const_iterator const_iterator; typedef boost::iterator_range<iterator> irange; typedef boost::iterator_range<const_iterator> cirange; std::string str = "hello world" ; const std::string cstr = "const world" ; // 1. 基本构建方法 boost::iterator_range<std::string::iterator> ir(str); boost::iterator_range<std::string::const_iterator> cir(str); // 2. 利用make_iterator_range(几种重载函数) irange r = boost::make_iterator_range(str); r = boost::make_iterator_range(str.begin(), str.end()); cirange r2 = boost::make_iterator_range(cstr); r2 = boost::make_iterator_range(cstr.begin(), cstr.end()); r2 = boost::make_iterator_range(str); assert (r == str); assert (r.size() == 11); irange r3 = boost::make_iterator_range(str, 1, -1); assert (boost::as_literal( "ello worl" ) == r3); irange r4 = boost::make_iterator_range(r3, -1, 1); // 这个也可以理解成复制构造 assert (str == r4); std::cout << r4 << std::endl; irange r5 = boost::make_iterator_range(str.begin(), str.begin() + 5); assert (r5 == boost::as_literal( "hello" )); } |
类型变化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
void test_range_type() { using namespace boost; // 数组 const int SIZE = 9; typedef int array_t[SIZE]; const array_t ca = {1, 2, 3, 4, 5, 6, 7, 8, 10}; assert ((is_same<range_iterator<array_t>::type, int * >::value)); assert ((is_same<range_value<array_t>::type, int >::value)); assert ((is_same<range_difference<array_t>::type, std:: ptrdiff_t >::value)); assert ((is_same<range_size<array_t>::type, std:: size_t >::value)); assert ((is_same<range_const_iterator<array_t>::type, const int * >::value)); assert (begin(ca) == ca); assert (end(ca) == ca + size(ca)); assert (empty(ca) == false ); } |
range-for是C++ 11新增特性,用于循环迭代一个“范围”,该“范围”类似于包含有begin()和end()方法的STL序列容器。所有的STL标准容器都适用于该“范围”,例如vector、string等等。数组也同样可以,只要定义了begin()和end()方法的任何“范围”都可以使用for来循环迭代容器里面的元素,如istream。
语法:
1
|
for ( range_declaration : range_expression) loop_statement |
上述代码的效果类似于:
1
2
3
4
5
6
7
8
9
|
(__range, __begin and __end are for exposition only): { auto && __range = range_expression ; for ( auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin) { range_declaration = *__begin; loop_statement } } |
迭代器begin_expr和end_expr可以被定义成如下类型:
* 如果__range是数组,(__range) 和 (__range + __bound)表示数组的范围
*如果__range是一个类,实现了begin()或end()方法,或者两个方法都实现了,此时begin_expr就表示 __range.begin(),而 end_expr则表示 __range.end()。
否则begin(__range)和end(__range)将通过基于与std名称空间关联的参数依赖查找规则来查找。
如果range_expression返回一个临时变量,它的生命周期到循环结束,如绑定到右值__range的,但要注意,临时嵌套在range_expression中的并没有延长其生命周期。
如同传统的for语句,关键字break可以提前结束循环,而continue可以继续循环。
example:
1
2
3
4
5
|
void f(vector< double >& v) { for ( auto x : v) cout << x << '/n' ; for ( auto & x : v) ++x; // 通过引用可以修改v中的值5 } |
for也可以用于迭代普通的数组,如:
1
2
|
for ( const auto x : { 1,2,3,5,8,13,21,34 }) cout << x << '/n' ; |
误区:
1
2
3
4
5
|
int * p = new int [2]; p[0] = 1; p[1] = 2; for ( auto x : p) cout << x << endl; |
编译器会报错误:
错误:对‘begin(int*&)’的调用没有匹配的函数
通过上面对for的介绍可以知道,for实现的机制就是依赖与容器中的begin()和end()方法。对于普通的数组,编译器默认已经实现了类似的方法。这里的p是一个指针,尽管它可以像数组一样使用,但是它并没有类似与begin()或end()的方法,当然会编译不通过。
以上内容根据个人理解结合互联网上相关作者介绍总结,错误再所难免。