Cycles in c++ like in python (range-based for)

六眼飞鱼酱① 提交于 2019-12-12 11:42:07

问题


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.


回答1:


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).



来源:https://stackoverflow.com/questions/40368949/cycles-in-c-like-in-python-range-based-for

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!