C++ range/xrange equivalent in STL or boost?
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.
Is there a compact equivalent to Python range() in C++/STL
In C++11, there's std::iota
:
#include <vector>
#include <numeric> //std::iota
int main() {
std::vector<int> x(10);
std::iota(std::begin(x), std::end(x), 0); //0 is the starting number
}
C++20 introduced a lazy version (just like Python) as part of the ranges library:
#include <iostream>
#include <ranges>
namespace views = std::views;
int main() {
for (int x : views::iota(0, 10)) {
std::cout << x << ' '; // 0 1 2 3 4 5 6 7 8 9
}
}
Numerical range iterators in boost?
boost::counting_iterator
#include <boost/iterator/counting_iterator.hpp>
std::for_each( boost::counting_iterator<int>(0),
boost::counting_iterator<int>(100),
do_something );
Is boost Range library going to be part of next C++ standard?
There's still a lot of discussion and work going on around ranges.
http://isocpp.org/blog/2013/01/update-from-the-ranges-study-group
It's unlikely that the existing boost ranges will be standardized in their current form. But that doesn't mean that you shouldn't go ahead and use the existing, available tools to improve your own programs.
Cycles in c++ like in python (range-based for)
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).
Does boost offer make_zip_range?
Boost.Range is providing combine()
function as zip_iterator
's range.
http://www.boost.org/doc/libs/1_56_0/libs/range/doc/html/range/reference/utilities/combine.html
Set std::vectorint to a range
You could use std::iota
if you have C++11 support or are using the STL:
std::vector<int> v(14);
std::iota(v.begin(), v.end(), 3);
or implement your own if not.
If you can use boost
, then a nice option is boost::irange
:
std::vector<int> v;
boost::push_back(v, boost::irange(3, 17));
Why boost uniform_int_distribution takes a closed range (instead of a half-open range, following common C++ usage)?
Only with closed ranges, you can create a uniform_int_distribution
, that produces any integer:
uniform_int_distribution<int> dist(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
If this would be a half-open range, you could never reach std::numeric_limits<int>::max()
, but only std::numeric_limits<int>::max() - 1
.
It's the same situation for std::uniform_int_distribution
in the C++11 standard library.
Half-open ranges for iterators are common, because one can easily express empty ranges (by setting begin == end
). This doesn't make sense for distributions.
Reference: Stephan T. Lavavej mentions this exact reason in his talk "rand() Considered Harmful" at Going Native 2013 (around minute 14). This talk is about C++11 <random>
, but of course the same reasoning applies to boost as well.
Related Topics
What's the Difference Between Span and Array_View in the Gsl Library
Why Do Linked Lists Use Pointers Instead of Storing Nodes Inside of Nodes
Purpose of a ".F" Appended to a Number
C++ Implicit Conversion (Signed + Unsigned)
Unresolved External Symbol "Public: Virtual Struct Qmetaobject Const * _Thiscall Parent
Under What Circumstances Are C++ Destructors Not Going to Be Called
How to Execute a Piece of Code Only Once
Is 'Bool' a Basic Datatype in C++
How to Typedef a Template Class
"Right" Way to Deallocate an Std::Vector Object
How to Use Qt Without Qmake or Qt Creator
Why "Universal References" Have the Same Syntax as Rvalue References
Opinions on Type-Punning in C++
Benefits of Using Reserve() in a Vector - C++
Use Getline and While Loop to Split a String
What Is the Right Approach When Using Stl Container for Median Calculation