Series: Iterator, Iterator Wrapper, Non-1-1 Wrapper
To make your own iterable range in C++ that you can loop over or make a vector out of (mine is called Numbers):
// Prints: // 3,4, for (auto n : Numbers(3, 5)) { std::cout << n << ","; } // Fills vec with 7, 8, 9 Numbers nums(7, 10); std::vectorvec{std::begin(nums), std::end(nums)};
you need to write a class that is an Input Iterator, and provide an instance as the begin and end of your range:
class Numbers { private: const int start_; const int end_; public: Numbers(int start, int end) : start_(start) , end_(end) {} myit begin() { return myit(start_); } myit end() { return myit(end_); } };
The hard bit is the Input Iterator:
#include <iterator> class myit { private: int value_; class intholder { int value_; public: intholder(int value): value_(value) {} int operator*() { return value_; } }; public: // Previously provided by std::iterator - see update below typedef int value_type; typedef std::ptrdiff_t difference_type; typedef int* pointer; typedef int& reference; typedef std::input_iterator_tag iterator_category; explicit myit(int value) : value_(value) {} int operator*() const { return value_; } bool operator==(const myit& other) const { return value_ == other.value_; } bool operator!=(const myit& other) const { return !(*this == other); } intholder operator++(int) { intholder ret(value_); ++*this; return ret; } myit& operator++() { ++value_; return *this; } };
Update: thanks to Anthony Williams for the correction on the postincrement operator – see Generating Sequences for more. Note the need to return a fiddly object that holds the answer we will give when the return value is dereferenced.
Using std::iterator as a base class actually only gives you some typedefs for free, but it’s worth it to get the standard names, and to be clear what we are trying to do. Update: std::iterator is deprecated in C++17 – just add the 5 typedefs yourself.
I suspect I might need to add some extra &s to make this good C++11 style?
Sadly, your postincrement operator isn’t right.
The requirement on postincrement is that *it++ returns the value at the iterator before the increment. Returning value_type from the postincrement operator doesn’t work for that: you would need to write just it++, which would be odd.
I explained how to write an iterator for exactly this scenario (numeric ranges) on my blog a couple of months ago: https://www.justsoftwaresolutions.co.uk/cplusplus/generating_sequences.html
Thanks Anthony – I wish I’d found your post when I was researching this. I was kind of hoping I’d get some corrections if I posted this!