What is the easiest way to do cycles in c ++ like in python?
for i in range(10): #or range(4, 10, 2) etc
foo(i)
I mean something simple and one-line like this
for(auto i: range(10)) //or range(4, 10, 2) or range(0.5, 1.0, 0.1) etc
foo(i);
but not like this:
std::vector<int> v(10);
std::iota(begin(v), end(v), 0);
for(auto i: v) {
foo(i);
}
Or this
for(auto i: []{vector<size_t> v(10); return iota(begin(v), end(v), 0), v;}() ) {
foo(i);
}
Of course, it is not difficult to use these examples or just for(;;)
but I hope there is a way to do it briefly and succinctly in python.
A Python-like range
notion is not provided out-of-the-box, but you could roll your own Range
class with a simple iterator, like this:
#include <iostream>
template <typename T>
class Range
{
public:
class iterator
{
public:
explicit iterator(T val, T stop, T step) : m_val(val), m_stop(stop), m_step(step) { }
iterator& operator ++ ()
{
m_val += m_step;
if ((m_step > 0 && m_val >= m_stop) ||
(m_step < 0 && m_val <= m_stop))
{
m_val = m_stop;
}
return *this;
}
iterator operator ++ (int) { iterator retval = *this; ++(*this); return retval; }
bool operator == (iterator other) const {return m_val == other.m_val;}
bool operator != (iterator other) const {return !(*this == other);}
T operator * () const { return m_val; }
private:
T m_val, m_stop, m_step;
};
explicit Range(T stop)
: m_start(0), m_stop(stop), m_step(1)
{ }
explicit Range(T start, T stop, T step = 1)
: m_start(start), m_stop(stop), m_step(step)
{ }
iterator begin() const { return iterator(m_start, m_stop, m_step); }
iterator end() const { return iterator(m_stop, m_stop, m_step); }
private:
T m_start, m_stop, m_step;
};
template <typename T>
Range<T> range(T stop) { return Range<T>(stop); }
template <typename T>
Range<T> range(T start, T stop, T step = 1) { return Range<T>(start, stop, step); }
int main()
{
for (auto i : range(10)) { std::cout << " " << i; }
std::cout << std::endl;
for (auto i : range(4, 10, 2)) { std::cout << " " << i; }
std::cout << std::endl;
for (auto i : range(0.5, 1.0, 0.1)) { std::cout << " " << i; }
std::cout << std::endl;
}
In order to support range-based for
, an iterator type and begin()
/end()
functions will do the job. (Of course my implementation above is quick and dirty, and could probably be improved.)
You will not get around rolling your own class like that, but once you have it, the usage is very much akin to the Python approach:
for (auto i : range(stop)) { ... }
for (auto i : range(start, stop, step)) { ... }
The example outputs (see live version here):
$ g++ -std=c++11 -o test test.cpp && ./test
0 1 2 3 4 5 6 7 8 9
4 6 8
0.5 0.6 0.7 0.8 0.9 1
If you only need integer ranges, you can also use boost::irange
(thanks to Yakk for the reminder).