Reputation: 31607
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
Upvotes: 7
Views: 4547
Reputation: 76805
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';
}
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.
Upvotes: 6
Reputation: 11831
This C++-11 feature is mostly a convenience shortcut for the most common case. If you want to exploit the full glory of C/C++ for
loop, you'd better do it the long (legacy) way. Trying smart tricks like defining strange increment operators will only lead to your gentle reader (more often than not, yourself a few weeks later) getting utterly confused. Just think what happens if in a week elsewhere you need to increment by one, not by two, and you don't notice the "smart" increment... It is a fine way to introduce subtle, impossible to spot bugs.
Upvotes: -3