A C++ iterator adapter which wraps and hides an inner iterator and converts the iterated type

前端 未结 7 1591
盖世英雄少女心
盖世英雄少女心 2020-12-09 04:25

Having toyed with this I suspect it isn\'t remotely possible, but I thought I\'d ask the experts. I have the following C++ code:

class IInterface
{
    virtual vo         


        
7条回答
  •  旧时难觅i
    2020-12-09 05:30

    Doesn't sound too complicated. You can define the iterator outside. You can also use typedefs. Something like this would fit i think. Note that it would be way cleaner if that MagicIterator would be not a free template, but a member of Item, typedefed in Container maybe. As it's now, there is a cyclic reference in it, which make it necassary to write some ugly workaround code.

    namespace detail {
        template
        struct constify;
    
        template
        struct constify {
            typedef T * type;
        };
    
        template
        struct constify {
            typedef T const * type;
        };
    }
    
    template
    struct MagicIterator;
    
    class Container
    {
    private:
        struct Item
        {
            Object* pObject;
        };
    
        std::list m_items;
    
    public:
    
        // required by every Container for the iterator
        typedef std::list iterator;
        typedef std::list const_iterator;
    
        // convenience declarations
        typedef MagicIterator< IInterface*, Container, iterator > 
            item_iterator;
        typedef MagicIterator< IInterface*, Container, const_iterator > 
            const_item_iterator;
    
        item_iterator Begin();
        item_iterator End();
    };
    
    template
    struct MagicIterator : 
        // pick either const T or T, depending on whether it's a const_iterator.
        std::iterator::type> {
        typedef std::iterator::type> base;
        MagicIterator():wrapped() { }
        explicit MagicIterator(InputIterator const& it):wrapped(it) { }
        MagicIterator(MagicIterator const& that):wrapped(that.wrapped) { }
    
        typename base::value_type operator*() {
            return (*wrapped).pObject->GetInterface();
        }
    
        MagicIterator& operator++() {
            ++wrapped;
            return *this;
        }
    
        MagicIterator operator++(int) {
            MagicIterator it(*this);
            wrapped++;
            return it;
        }
    
        bool operator==(MagicIterator const& it) const {
            return it.wrapped == wrapped;
        }
    
        bool operator!=(MagicIterator const& it) const {
            return !(*this == it);
        }
    
        InputIterator wrapped;
    };
    
    // now that the iterator adepter is defined, we can define Begin and End
    inline Container::item_iterator Container::Begin() {
        return item_iterator(m_items.begin());
    }
    
    inline Container::item_iterator Container::End() {
        return item_iterator(m_items.end());
    }
    

    Now, start using it:

    for(MagicIterator it = c.Begin(); it != c.End(); ++it) {
        // ...
    }
    

    You can also use a iterator mixin provided by boost, which works like the input version of boost::function_output_iterator. It calls your iterator's operator() which then returns the appropriate value, doing what we do above in our operator* in principle. You find it in random/detail/iterator_mixin.hpp. That would probably result in fewer code. But it also requires to wrack up our neck to ensure the friend-stuff because Item is private and the iterator isn't defined inside Item. Anyway, good luck :)

提交回复
热议问题