Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract iterator for underlying collections

So basically what I want to do is to have a pure virtual method returning an iterator to an arbitrary collection of a concrete type, e.g in pseudo code:

virtual Iterator<T> getIterator() const = 0;

The user of this class actually don't care what implementation the child class uses. It could be a set, vector, list, array etc.

I'm aware of the std::iterator class but I cant find a way to specify it correctly in order to work with a simple vector.

virtual std::iterator<std::random_access_iterator_tag,T> getIterator() const = 0;

myVector.begin() // compilation error in implementation

defining std::iterator with const T as type parameter hasn't worked too. I also tried leaving T and instead defining the pointer and reference types as const T* and const T&.

By taking a look at the std::vector implementation, I found out that std::vector::const_iterator actually derives from _Iterator012 deriving from _Iterator_base.

It really bugs me that there isn't any way to work with arbitrary collections in std. Implementing my classes as templates like in <algorithm> is not an option for me due two reasons:

  • No control over the actual value type
  • I simply don't want to make my classes templates complicating my design a lot and making things less flexible.

The used type parameter T was just for demonstration, actually this is a concrete type.

like image 502
Sebastian Hoffmann Avatar asked Dec 02 '12 15:12

Sebastian Hoffmann


1 Answers

Here's a basic and very rudimentary skeleton approach using type erasure. You'll have to fill in a lot of missing details, though!

#include <memory>

template <typename T>
class TEIterator
{
    struct TEImplBase
    {
        virtual ~TEImplBase() { }
        virtual std::unique_ptr<TEImplBase> clone() const = 0;
        virtual void increment() = 0;
        virtual T & getValue() = 0;
        T * getPointer() { return std::addressof(getValue()); }
    };

    template <typename Iter>
    struct TEImpl
    {
        Iter iter;

        TEImpl(Iter i) : iter(i) { }

        virtual T & getValue()
        { return *iter; }

        virtual std::unique_ptr<TEImplBase> clone() const
        { return std::unique_ptr<TEImplBase>(new TEImpl<Iter>(*this)); }

        virtual void increment()
        { ++iter; }
    };

    std::unique_ptr<TEImplBase> impl;

public:

    template <typename T>
    TEClass(T && x)
    : impl(new TEImpl<typename std::decay<T>::type>(std::forward<T>(x)))
    {
    }

    TEClass(TEClass && rhs) = default;

    TEClass(TEClass const & rhs) : impl(rhs.impl.clone()) { }

    TEIterator & operator++()
    {
        impl->increment();
        return *this;
    }

    T & operator*() { return impl->getValue(); }
    T * operator->() { return impl->getPointer(); }
};

Usage:

std::vector<int> v;
std::deque<int> dq;

TEIterator<int> a = v.begin(), b = dq.end();
like image 53
Kerrek SB Avatar answered Sep 25 '22 00:09

Kerrek SB