比如需要遍历数值范围[5,10),直观的方法是:
for (int i = 5; i < 10; i++) {
.....
}
c++11的auto关键字,可以不指定数据类型,如下:
for (auto i = 5; i < 10; i++) {
.....
}
c++11的auto关键字,还可以遍历容器,如下:
std::vector<int> v = {5,6,7,8,9};
for (auto i: v) {
.....
}
c++11的auto的区间迭代功能,功能就是大幅减少不必要代码开发。需要这个容器能够:
1、有begin()和end()方法,返回容器头尾的迭代器;
2、支持"*"(取值)、"++"(迭代器前移)、"!="(判断迭代器是否相同)这三个运算符重载
STL的vector、set、map、unordered_map、unordered_set等容器都支持。
那么也没有办法也实现一个,能够快速简单遍历任意数值区间的容器呢,比如遍历[5,10)的数值范围
同样是实现上面的1和2里的5个方法,即begin、end、*、++、!=,这5个方法;
下面是思路:
1、需要实现两个类型,分别是"数值范围容器类"和"数值范围容器的迭代器类",前者命名为Range,后者命名为Iterator,
循环体就如下:
for (auto i: Range(5, 10)) {
..... //i 依次为5、6、7、8、9
}
Range类支持begin()和end()方法,它们都返回两个迭代器Iterator分别是头尾数据对应的迭代器
Range在迭代过程中,每次返回一个迭代器Iterator
2、迭代器Iterator支持*、++、!=这3个方法
*:获取迭代器当前对应的值
++: 迭代器前移
!=: 判断两个迭代器是否相同
3、如何设计Iterator:
简单就是一个区间,没有逻辑的关联,不妨每个数值对应一种迭代器
*: 就对应这个数值
++: 数值加1,再获取这个数值
!=: 两个迭代器获取各自的数值,然后判断是否相等
对于!=,因为数值区间的数值不会重复,所以就可以简单的这样处理
class Iterator {
int64_t value_;
int64_t GetValue () const {
return value_;
}
public:
Iterator (uint64_t value): value_(value) {}
bool operator!= (const Iterator &other) const {
return GetValue() != other.GetValue();
}
uint64_t operator* () const {
return GetValue();
}
const Iterator &operator++ () {
++value_;
return *this;
}
};
Range类,接受数值区间的头和尾,进而的begin()和end(),返回两个对应的Iterator迭代器对象
class Range {
uint64_t begin_;
uint64_t end_;
public:
Range(uint64_t begin, uint64_t end): begin_(begin), end_(end) {}
Iterator begin() {
return Iterator(begin_);
}
Iterator end() {
return Iterator(end_);
}
};
这样在遍历过程中,首先由begin()获取到第一个迭代器Iterator对象,然后它不断调用"++"前移,直到发现"!="end()的迭代器对象不再成立,为止:
测试代码如下:
for (auto i: common::Range(5, 10)) {
std::cout << i << std::endl;//依次输出5、6、7、8、9
}
总结:
1、支持begin()、end()、*、++、!=五个方法容器,可以使用auto循环迭代
2、原则上,这样的容器,应包括容器类和容器迭代器类,
容器类应支持begin()和end()两方法,返回头尾对应的迭代器对象;
容器迭代器类,应支持*、++、!=这三个方法,分别对应所需的取值、前移、判断位置是否相同;
3、循环首先由容器类的begin()方法获取到头对象对应的迭代器,并不断调用"*"取值、"++"前移,直到调用"!="发现迭代到end()方法获取到的尾对象对应的迭代器为止;