Search code examples
c++boostc++11iteratorboost-iterators

indirect_iterator for map<T, shared_ptr<U>>


I'm trying to implement an iterator of map<T, shared_ptr<U>> that "removes" shared_ptr, i.e. dereferences to pair<T, U&>. I need this to adapt my wrapper over map to range-based for loop.

boost::indirect_iterator seems like something designed for such a need. I tried this:

typedef std::map<int, std::shared_ptr<int>> M;
typedef boost::indirect_iterator<M::iterator, std::pair<int, int>> It;

This doesn't work because of indirect_iterator requirement:

The expression *v, where v is an object of iterator_traits::value_type, shall be valid expression and convertible to reference.

Is it possible to use boost::indirect_iterator for this task? If no, can I do this with boost::iterator_adaptor?


Solution

  • Thanks to @Xeo comment, the solution is to use Boost.Range. What I managed to get from VC10

    #include <boost/range/adaptor/map.hpp>
    #include <boost/range/adaptor/indirected.hpp>
    
    #if defined(_MSC_VER) && _MSC_VER <= 1600 // VC10
        template< class T >
        typename std::add_rvalue_reference<T>::type declval();
    #endif
    
    class Wrapper
    {
    private:
        typedef std::map<T, std::shared_ptr<U>> Container;
    
    public:
        typedef decltype(declval<Container&>() | boost::adaptors::map_values | boost::adaptors::indirected) IteratorRange;
        typedef decltype(declval<Container&>() | boost::adaptors::map_values | boost::adaptors::indirected) ConstIteratorRange;
        typedef IteratorRange::iterator Iterator;
        typedef ConstIteratorRange::const_iterator ConstIterator;
    
        Iterator begin()
        {
            return iteratorRange().begin();
        }
    
        // by analogy
        ConstIterator begin() const;
        ConstIterator cbegin() const;
        Iterator end();
        ConstIterator end() const;
        ConstIterator cend() const;
    
    private:
        IteratorRange iteratorRange()
        {
            return container | boost::adaptors::map_values | boost::adaptors::indirected;
        }
    
        ConstIteratorRange iteratorRange() const;
    
    private:
        Container container;
    };