Is there a range class in C ++ 11 for use with loop based range?

I realized that I wrote this a little back:

template <long int T_begin, long int T_end> class range_class { public: class iterator { friend class range_class; public: long int operator *() const { return i_; } const iterator &operator ++() { ++i_; return *this; } iterator operator ++(int) { iterator copy(*this); ++i_; return copy; } bool operator ==(const iterator &other) const { return i_ == other.i_; } bool operator !=(const iterator &other) const { return i_ != other.i_; } protected: iterator(long int start) : i_ (start) { } private: unsigned long i_; }; iterator begin() const { return iterator(T_begin); } iterator end() const { return iterator(T_end); } }; template <long int T_begin, long int T_end> const range_class<T_begin, T_end> range() { return range_class<T_begin, T_end>(); } 

And this allows me to write things like this:

 for (auto i: range<0, 10>()) { // stuff with i } 

Now I know that I wrote, perhaps not the best code. And perhaps there is a way to make it more flexible and useful. But it seems to me that something like this should have become part of the standard.

The way it is? Has any new library been added for iterators over a whole series of integers or maybe to the total number of computed scalar values?

+93
c ++ c ++ 11 std
Aug 25 '11 at 5:12
source share
8 answers

The standard C ++ library does not have one , but Boost.Range has boost :: counting_range , which is definitely suitable. You can also use boost :: irange , which is a bit more focused.

The C ++ 20 range library allows you to do this through view::iota(start, end) .

+54
Aug 25 2018-11-11T00:
source share

As far as I know, there is no such class in C ++ 11.

Anyway, I tried to improve your implementation. I made it not a template, since I do not see any advantage in creating a template. On the contrary, it has one main drawback: you cannot create a range at runtime, since you need to know the template arguments at compile time.

 //your version auto x = range<m,n>(); //m and n must be known at compile time //my version auto x = range(m,n); //m and n may be known at runtime as well! 

Here is the code:

 class range { public: class iterator { friend class range; public: long int operator *() const { return i_; } const iterator &operator ++() { ++i_; return *this; } iterator operator ++(int) { iterator copy(*this); ++i_; return copy; } bool operator ==(const iterator &other) const { return i_ == other.i_; } bool operator !=(const iterator &other) const { return i_ != other.i_; } protected: iterator(long int start) : i_ (start) { } private: unsigned long i_; }; iterator begin() const { return begin_; } iterator end() const { return end_; } range(long int begin, long int end) : begin_(begin), end_(end) {} private: iterator begin_; iterator end_; }; 

Test code:

 int main() { int m, n; std::istringstream in("10 20"); if ( in >> m >> n ) //using in, because std::cin cannot be used at coliru. { if ( m > n ) std::swap(m,n); for (auto i : range(m,n)) { std::cout << i << " "; } } else std::cout <<"invalid input"; } 

Output:

10 11 12 13 14 15 16 17 18 19

Onine demo .

+43
Aug 25 2018-11-11T00:
source share

I wrote a library called range for exactly the same purpose, except that it is a runtime range, and the idea in my case came from Python. I counted the compiled version, but in my humble opinion there is no real advantage to getting the compile time version. You can find the library on the bitpack, and it is licensed under Boost: Range . This is a single-heading library compatible with C ++ 03 and working like a charm with loops based on loops in C ++ 11 :)

Features :

  • A real container with random access with all the bells!

  • Ranges can be compared lexicographically.

  • Two functions exist (returns bool) and find (returns an iterator) to check for a number.

  • The library is tested using CATCH .

  • Examples of basic use are, working with standard containers, working with standard algorithms, and working with a range based on loops.

Here is a one-minute introduction . Finally, I welcome any suggestion about this tiny library.

+11
Aug 28 2018-11-11T00:
source share

I found that boost::irange was much slower than the canonical integer loop. Therefore, I settled on the following much simpler solution using a preprocessor macro:

 #define RANGE(a, b) unsigned a=0; a<b; a++ 

Then you can do this:

 for(RANGE(i, n)) { // code here } 

This range automatically starts from zero. It can be easily expanded to start with a given number.

+4
Aug 11 '14 at 10:49 on
source share

Here is a simpler form that works well for me. Are there any risks in my approach?

r_iterator is a type that behaves as much as possible, like a long int . Therefore, many operators, such as == and ++ , simply go to long int . I “expose” the base long int through operator long int and operator long int & conversions.

 #include <iostream> using namespace std; struct r_iterator { long int value; r_iterator(long int _v) : value(_v) {} operator long int () const { return value; } operator long int& () { return value; } long int operator* () const { return value; } }; template <long int _begin, long int _end> struct range { static r_iterator begin() {return _begin;} static r_iterator end () {return _end;} }; int main() { for(auto i: range<0,10>()) { cout << i << endl; } return 0; } 

( Edit: - we can create range static methods instead of const.)

+2
Dec 20 '11 at 15:50
source share

It may be a little late, but I just saw this question, and I used this class for a while now:

 #include <iostream> #include <utility> #include <stdexcept> template<typename T, bool reverse = false> struct Range final { struct Iterator final{ T value; Iterator(const T & v) : value(v) {} const Iterator & operator++() { reverse ? --value : ++value; return *this; } bool operator!=(const Iterator & o) { return o.value != value; } T operator*() const { return value; } }; T begin_, end_; Range(const T & b, const T & e) : begin_(b), end_(e) { if(b > e) throw std::out_of_range("begin > end"); } Iterator begin() const { return reverse ? end_ -1 : begin_; } Iterator end() const { return reverse ? begin_ - 1: end_; } Range() = delete; Range(const Range &) = delete; }; using UIntRange = Range<unsigned, false>; using RUIntRange = Range<unsigned, true>; 

Using:

 int main() { std::cout << "Reverse : "; for(auto i : RUIntRange(0, 10)) std::cout << i << ' '; std::cout << std::endl << "Normal : "; for(auto i : UIntRange(0u, 10u)) std::cout << i << ' '; std::cout << std::endl; } 
+1
Jan 11 '14 at
source share

You tried to use

 template <class InputIterator, class Function> Function for_each (InputIterator first, InputIterator last, Function f); 

Most of the time is suitable for counting.

eg.

 template<class T> void printInt(T i) {cout<<i<<endl;} void test() { int arr[] = {1,5,7}; vector v(arr,arr+3); for_each(v.begin(),v.end(),printInt); } 

Note that printInt can replace OFC with lambda in C ++ 0x. There may also be another small variation of this use (strictly for random_iterator)

  for_each(v.begin()+5,v.begin()+10,printInt); 

For Fwd only iterator

  for_each(advance(v.begin(),5),advance(v.begin(),10),printInt); 
0
Aug 25 2018-11-11T00:
source share

You can easily generate an increasing sequence in C ++ 11 with std :: iota ():

 #include <iostream> #include <vector> #include <iterator> #include <algorithm> template<typename T> std::vector<T> range(T start, T end) { std::vector<T> r(end+1-start, T(0)); std::iota(r.begin(), r.end(), T(start));//increasing sequence return r; } int main(int argc, const char * argv[]) { for(auto i:range<int>(-3,5)) std::cout<<i<<std::endl; return 0; } 
-one
Jan 25 '16 at 22:42
source share



All Articles