Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ range for loops with custom step

Tags:

c++

In c++ 11 you can iterate over a container with range for loops :

for (auto i : vec) { /* do stuff */ }

Besides the drawback that iterating in reverse is not that obvious (C++11 reverse range-based for-loop) it is also limited by the fact that you cannot define a custom step for the iteration.

Is there a way to do it? I can't get my mind around it, but imagine an adaptor like

template<typename T>
struct step
{
    T const &container;
    step( T const &cont, int aStep);
    // provide begin()  / end() member functions
    // maybe overload the ++ operator for the iterators ? 
};

for (auto i : step(vec, i)) {}

EDIT:

The discussion is about achieving semantics similar to Pythons generators https://wiki.python.org/moin/Generators eg the range() function. Please don't make pointless comments on how this would increase code complexity, no one ever went back to hand written for loops in Python, and even though this is not the case in C++ (I should say that again: this is NOT the case in c++) I wanted to explore ways to write

for (auto i : range(vec, step))

since the new standard provides the facilities to use such syntax. The range() function would be a one time effort and the user of the code would not have to worry about the specifics of the imlpementation

like image 665
Nikos Athanasiou Avatar asked Feb 02 '14 22:02

Nikos Athanasiou


People also ask

Are there range-based for loops in C?

Range-based for loop (since C++11) Executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.

Are range-based loops faster?

Range-for is as fast as possible since it caches the end iterator[citationprovided], uses pre-increment and only dereferences the iterator once. Then, yes, range-for may be slightly faster, since it's also easier to write there's no reason not to use it (when appropriate).

How do you create a range in CPP?

Use the range-based for statement to construct loops that must execute through a range, which is defined as anything that you can iterate through—for example, std::vector , or any other C++ Standard Library sequence whose range is defined by a begin() and end() .

What is use of auto in for loop?

Range-based for loop in C++ Often the auto keyword is used to automatically identify the type of elements in range-expression. range-expression − any expression used to represent a sequence of elements.


1 Answers

Range-based for,

for ( range_declaration : range_expression ) loop_statement

just takes a begin and an end iterator, performing prefix operator++ on them like this:

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

Where begin_expr and end_expr "do the right thing" (see link above for the details). What you can do, is supply a proxy object as range_expression, so that its iterators do what you want. A prime example is Boost's range adaptors library:

#include <boost/range/adaptor/strided.hpp>
#include <boost/range/adaptor/reversed.hpp>

#include <iostream>
#include <vector>

int main()
{
  std::vector<int> input = {1,2,3,4,5,6,7,8,9,10};

  for(const auto& element : boost::adaptors::reverse(input))
    std::cout << element << '\n';
  std::cout << '\n';

  for(const auto& element : boost::adaptors::stride(input,2))
    std::cout << element << '\n';
}

Live demo here.

This is quite similar and virtually equally (if not more) powerful to Python range. You can easily write your own adaptors, see e.g. the answers to this question.

like image 93
rubenvb Avatar answered Sep 21 '22 20:09

rubenvb