range-based for loopc++11中引入的新的语法,例如:

// c++11
std::vector<int> arr {1, 2, 3, 4};
for (const auto &each : arr) {
  std::cout << each << " ";
}
std::cout << std::endl;
// 输出
// 1 2 3 4

语法解释

for (range_declaration : range_expression) {
    loop_statement
}

这个是range-based for loop的语法,这个语法在c++11c++14标准等同于

{
    auto && __range = range_expression;
    for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++_begin) {
        range_declaration = *__begin;
        loop_statement
    }
}

c++17标准中等同于

{
    auto && __range = range_expression;
    auto __begin = begin_expr;
    auto __end = end_expr;
    for ( ; __begin != __end; ++__begin) {
        range_declaration = *__begin;
        loop_statement
    }
}

range-based for loop解析的三个原则

  1. 如果range_expression为数组

    begin_expr = __range;
    end_expr = (__range + __bound)

    其中,__bound是固定大小数组的长度(如果长度未知,则程序是有问题的,一般情况编译器会报错)

  2. 如果range_expression是一个类,且这个类有名为beginend的成员函数

    begin_expr = __range.begin();
    end_expr = __range.end();
  3. 如果不满足上述要求,那么编译器会使用ADL查找符合条件的函数,如下所示

    begin_expr = begin(__range);
    end_expr = end(__range);
    这里的begin函数和end函数可以在命名空间中,ADL都会找到匹配的函数

自定义类的range-based for loop

根据上面三个原则中的后两个,以及“语法解释”中C++扩展的代码可知,我们的自定义类Foo需要实现

  1. beginend方法,这两个方法要么是Foo的成员函数,要么这两个方法接受Foo作为其参数

    根据“range-based for loop解析的三个原则”中的第二第三点
  2. beginend方法需要返回某各类,我们这里命名为FooInterator,这个类需要实现!=++的重载

    根据“语法解析”中,__begin != __end++__begin这两部分代码
    FooIterator也可以是指针,指针原生支持!=++运算符

例子

例子1

#include <iostream>

class IntArray3 {
 public:
  IntArray3() : arr_{1, 2, 3} {}

  int* begin() { return arr_; }
  int* end() { return arr_ + 3; }

 private:
  int arr_[3];
};

int main(int argc, char** argv) {
  IntArray3 arr;
  for (const auto &each : arr) {
    std::cout << each << " ";
  }
  std::cout << std::endl;
  return -1;
}

例子2

#include <iostream>

class IntArray3 {
 public:
  IntArray3() : arr_{1, 2, 3} {}

 private:
  int arr_[3];
  friend int* begin(IntArray3 &arr);
  friend int* end(IntArray3 &arr);
};

int* begin(IntArray3 &arr) {
  return arr.arr_;
}

int* end(IntArray3 &arr) {
  return arr.arr_ + 3;
}

int main(int argc, char** argv) {
  IntArray3 arr;
  for (const auto &each : arr) {
    std::cout << each << " ";
  }
  std::cout << std::endl;
  return -1;
}

Ref

  1. https://en.cppreference.com/w/cpp/language/range-for
Last modification:June 10, 2021
If you think my article is useful to you, please feel free to appreciate