开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
在C++11后,增加了一个新的东西,是针对于for循环而言的。
是一种基于迭代器的for each循环的样子
在其他语言中可能早就有这个玩意了,而在C++11之前,这个语法糖并没有,反而是在库中有一个这样的东西。
其类似于这种:
int main() {
std::vector<int> ve{1, 2, 3, 4};
{
struct out {
void operator()(const int &x) { std::cout << x << " "; }
};
std::for_each(std::begin(ve), std::end(ve), out());
}
return 0;
}
利用仿函数和迭代器结合来完成遍历这一件事情的。
为什么要这样搞呢,因为在c++98用迭代器访问可能有点麻烦 (
std::vector<int> ve{1, 2, 3, 4};
{
for (std::vector<int>::iterator it = ve.begin(); it != ve.end(); ++it) {
std::cout << *it << " ";
}
}
上面那个迭代器还是一个简单的迭代器,若是碰上元素比较复杂的情况,还是要写上许多累赘代码的。
c++ 一直贯穿可以加入标准库的就先不要当作特性来搞。
所以,c++98中 for_each 作为一个库函数登场了
但是,c++98中没有lambda表达式,要通过仿函数的方式来处理遍历的对象。
于是,还是比较繁琐,于是,在c++11中,增强for循环这个语法糖来解决这个问题了。
c++ 的 增强for循环 形如这种:
for (变量类型 变量名 : 容器) {
... 处理
}
和python、Java的foreach类似。
其实Java的foreach也相当于是一个语法糖嘛。
那这个语法糖是如何实现的呢?
和c++98的for_each一样,是通过 它的迭代器来达到这一目的。
至于为什么可以自动推导迭代器,用的还是类型萃取那一套的技巧。
增强for循环至少要满足如下条件:
容器类型有 begin() end() 这两个成员函数 或者 begin() end()的函数的重载
容器返回一个迭代器,这个迭代器至少满足 重载了 operator!=, operator*, operator++ 三个运算符
为什么要满足如上条件才能用呢?
证明增强for循环是语法糖的最好依据
for (std::vector<int>::iterator it = ve.begin(); it != ve.end(); ++it) {
std::cout << *it << " ";
}
比如我们可以自定义一个range,让其满足基本的使用条件。
struct range {
private:
int start_, end_;
struct iter {
int val;
iter(int x) : val(x) {}
int operator*() const { return val; }
bool operator!=(iter rhs) const { return val != rhs.val; }
iter operator++() { return val++, *this; }
};
public:
using range_iter = range::iter;
range(int start, int end) : start_(start), end_(end) {}
range_iter begin() const { return start_; }
range_iter end() const { return end_; }
};
根据以上range类而来的迭代
for (int v : range(1, 4)) {
std::cout << v << " ";
}
对应着下列的语法糖
{
range && __range1 = range(1, 4);
range::iter __begin1 = __range1.begin();
range::iter __end1 = __range1.end();
for(; __begin1.operator!=(range::iter(__end1)); __begin1.operator++()) {
int v = __begin1.operator*();
std::operator<<(std::cout.operator<<(v), " ");
}
}