C++ iterator example (and an iterable range)

May 11, 2017 [C++, Tech]

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::vector vec{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?