Demystifying C++ - Range-Based for Loops

From emmtrix Wiki
Jump to navigation Jump to search


Range-based for loops in modern C++ offer a neat and intuitive way to iterate over the elements of a container or array. Compared to traditional loops where indices or iterators need to be explicitly managed, range-based for-loops offer a more concise and less error-prone syntax.

Here's the substitute code for the loop that is written in the C++17 standard:

Substitute Code
for (range-declaration : range-expression) {
  ...
}

auto && __range = range-expression;
auto __begin = begin-expr;
auto __end = end-expr;
for ( ; __begin != __end; ++__begin) {
  range-declaration = *__begin;

  ...
}

The following example showcases the C-code for a simple instance with `std::initializer_list`. The code follows the principle of the substitute code:

Range-based for loop

with std::initializer_list

#include <initializer_list>

void work(int);

void func() {
  for (int i : {1, 2, 3}) {
    work(i);
  }
}

struct std::initializer_list<int> {
  const int *__begin_;
  size_t __size_;
};

inline const int *std::initializer_list<int>::begin(const struct std::initializer_list<int> *this) {
  return this->__begin_;
}
inline const int *std::initializer_list<int>::end(const struct std::initializer_list<int> *this) {
  return this->__begin_ + this->__size_;
}

void work(int);

void func(void) {
  {
    const int init[3] = {1, 2, 3};
    struct std::initializer_list<int> tmpExpr1 = {init, 3};
    struct std::initializer_list<int> *__range1 = &tmpExpr1;
    const int *__begin1 = std::initializer_list<int>::begin(__range1);
    const int *__end1 = std::initializer_list<int>::end(__range1);
    for (; __begin1 != __end1; ++__begin1) {
      int i = *__begin1;
      work(i);
    }
  }
}

This mechanism ensures that the correct lifespan of temporary variables is maintained, preserving the intended behavior of the original C++ code when translating to C.