C++ range/xrange equivalent in STL or boost?

std::iota (not yet standardized) is kinda like range. Doesn't make things any shorter or clearer than an explicit for loop, though.

#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main() {
    std::vector<int> nums(5);
    std::iota(nums.begin(), nums.end(), 1);
    std::copy(nums.begin(), nums.end(),
            std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
    return 0;
}

Compile with g++ -std=c++0x; this prints "1 2 3 4 5 \n".


well, here is what i wrote, since there does not seem to be one. the generator does not use any internal storage besides single integer. range object can be passed around and used in nested loops.

there is a small test case.

#include "iostream"
#include "foreach.hpp"

#include "boost/iterator/iterator_categories.hpp"

struct range {

  struct iterator_type {
    typedef int value_type;
    typedef int difference_type;
    typedef boost::single_pass_traversal_tag iterator_category;
    typedef const value_type* pointer;
    typedef const value_type & reference;

    mutable value_type value;
    const difference_type increment;

    iterator_type(value_type value, difference_type increment = 0)
      : value(value), increment(increment) {}

    bool operator==(const iterator_type &rhs) const {
      return value >= rhs.value;
    }
    value_type operator++() const { return value += increment; }
    operator pointer() const { return &value; }
  };

  typedef iterator_type iterator;
  typedef const iterator_type const_iterator;

  int first_, last_, increment_;

  range(int last) : first_(0), last_(last), increment_(1) {}
  range(int first, int last, int increment = 1)
    : first_(first), last_(last), increment_(increment) {}

  iterator begin() const {return iterator(first_, increment_);}
  iterator end() const {return iterator(last_);}
};

int test(const range & range0, const range & range1){
  foreach(int i, range0) {
    foreach(int j, range1) {
      std::cout << i << " " << j << "\n";
    }
  }
}

int main() {
  test(range(6), range(3, 10, 3));
}

Boost has counting_iterator as far as I know, which seems to allow only incrementing in steps of 1. For full xrange functionality you might need to implement a similar iterator yourself.

All in all it could look like this (edit: added an iterator for the third overload of xrange, to play around with boost's iterator facade):

#include <iostream>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/foreach.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <cassert>

template <class T>
boost::iterator_range<boost::counting_iterator<T> > xrange(T to)
{
    //these assertions are somewhat problematic:
    //might produce warnings, if T is unsigned
    assert(T() <= to);
    return boost::make_iterator_range(boost::counting_iterator<T>(0), boost::counting_iterator<T>(to));
}

template <class T>
boost::iterator_range<boost::counting_iterator<T> > xrange(T from, T to)
{
    assert(from <= to);
    return boost::make_iterator_range(boost::counting_iterator<T>(from), boost::counting_iterator<T>(to));
}

//iterator that can do increments in steps (positive and negative)
template <class T>
class xrange_iterator:
    public boost::iterator_facade<xrange_iterator<T>, const T, std::forward_iterator_tag>
{
    T value, incr;
public:
    xrange_iterator(T value, T incr = T()): value(value), incr(incr) {}
private:
    friend class boost::iterator_core_access;
    void increment() { value += incr; }
    bool equal(const xrange_iterator& other) const
    {
        //this is probably somewhat problematic, assuming that the "end iterator"
        //is always the right-hand value?
        return (incr >= 0 && value >= other.value) || (incr < 0 && value <= other.value);
    }
    const T& dereference() const { return value; }
};

template <class T>
boost::iterator_range<xrange_iterator<T> > xrange(T from, T to, T increment)
{
    assert((increment >= T() && from <= to) || (increment < T() && from >= to));
    return boost::make_iterator_range(xrange_iterator<T>(from, increment), xrange_iterator<T>(to));
}

int main()
{
    BOOST_FOREACH(int i, xrange(10)) {
        std::cout << i << ' ';
    }
    BOOST_FOREACH(int i, xrange(10, 20)) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
    BOOST_FOREACH(int i, xrange(0, 46, 5)) {
        std::cout << i << ' ';
    }
    BOOST_FOREACH(int i, xrange(10, 0, -1)) {
        std::cout << i << ' ';
    }
}

As others are saying, I don't see this buying you much over a normal for loop.


Boost irange should really be the answer (ThxPaul Brannan)

I'm adding my answer to provide a compelling example of very valid use-cases that are not served well by manual looping:

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/irange.hpp>

using namespace boost::adaptors;

static int mod7(int v) 
    { return v % 7; }

int main() 
{
    std::vector<int> v;

    boost::copy(
            boost::irange(1,100) | transformed(mod7), 
            std::back_inserter(v));

    boost::sort(v);

    boost::copy(
            v | reversed | uniqued, 
            std::ostream_iterator<int>(std::cout, ", "));
}

Output: 6, 5, 4, 3, 2, 1, 0,

Note how this resembles generators/comprehensions (functional languages) and enumerables (C#)

Update I just thought I'd mention the following (highly inflexible) idiom that C++11 allows:

for (int x : {1,2,3,4,5,6,7})
    std::cout << x << std::endl;

of course you could marry it with irange:

for (int x : boost::irange(1,8))
    std::cout << x << std::endl;