C++ iterator wrapper/adaptor example

May 12, 2017 [C++, Tech]

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 functionstd::toupper in two places.

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