C++ iterator wrapper/adaptor example

Series: Iterator, Iterator Wrapper, Non-1-1 Wrapper

If you want to wrap an iterable range with another that transforms the underlying iterators in some way and allows looping or constructing other objects:

for (auto ch : Upper("abcdef"))
{
    // Prints "ABCDEF"
    std::cout << ch;
}
Upper up(std::string("fOo"));
std::string newfoo(std::begin(up), std::end(up));
assert(newfoo == "FOO");

then, similar to an ordinary iterable range you will need to make a range class and a iterator class:

class myit
{
private:
    std::string::const_iterator wrapped_;
    class charholder
    {
        const char value_;
    public:
        charholder(const char value) : value_(value) {}
        char operator*() const { return value_; }
    };
public:
    // Previously provided by std::iterator
    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(std::string::const_iterator wrapped) : wrapped_(wrapped) {}
    value_type operator*() const { return std::toupper(*wrapped_); }
    bool operator==(const myit& other) const { return wrapped_ == other.wrapped_; }
    bool operator!=(const myit& other) const { return !(*this == other); }
    charholder operator++(int)
    {
        charholder ret(std::toupper(*wrapped_));
        ++wrapped_;
        return ret;
    }
    myit& operator++()
    {
        ++wrapped_;
        return *this;
    }
};


class Upper
{
private:
    const std::string str_;
public:
    Upper(const std::string str) : str_(str) {}
    myit begin() { return myit(std::begin(str_)); }
    myit end()   { return myit(std::end(str_)); }
};

Notice the need to call the transforming/adapting function
std::toupper in two places.

Update: std::iterator is deprecated in C++17, so removed.

3 thoughts on “C++ iterator wrapper/adaptor example”

  1. Hello Andy,
    firstly many thanks for the great adaptor example. But what I don’t understand is why you have implemented the inner class charholder used in charholder operator++(int). Is it really necessary? Thanks

  2. Hi Ramyken, Thanks! See the comments on the first post in this series here: https://www.artificialworlds.net/blog/2017/05/11/c-iterator-example-and-an-iterable-range/ . I thought very similarly to you when I wrote that, and Anthony Williams (author of C++ Concurrency In Action) very kindly put me straight. The postincrement operator has to return the value at the iterator before it was incremented. (That is why, in general, you should not use it…).

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.