Search code examples
c++boostiteratorweak-ptr

std::set of boost::weak_ptr<T> - Getting const_iterator to const T?


I have class containing an std::set of boost::weak_ptr<T>. I have two functions begin() and end() that return an iterator to the container. However, I don't want clients to be able to modify T. Simply returning a const_iterator won't work, because the T pointed to by the boost::weak_ptr will be editable.

What I want to do is return a const_iterator to std::set<boost::weak_ptr<T const> >. Casting from std::set<boost::weak_ptr<T> >::const_iterator does not work. Is there any way to get the behaviour I want?


Solution

  • You can write a transform iterator to convert the weak_ptr<T> to a weak_ptr<const T>. Since you're already using Boost, you can use boost::transform_iterator:

    #include <boost/iterator/transform_iterator.hpp>
    #include <boost/shared_ptr.hpp>
    #include <boost/weak_ptr.hpp>
    
    #include <set>
    
    // Functor to transform a weak_ptr<T> to a weak_ptr<const T>
    template <typename T>
    struct make_weak_ptr_const
        : std::unary_function<boost::weak_ptr<T>, boost::weak_ptr<const T> >
    {
        boost::weak_ptr<const T> operator()(const boost::weak_ptr<T>& p) const
        {
            return p;
        }
    };
    
    struct S { };
    
    // Container demonstrating use of make_weak_ptr_const:
    struct my_awesome_container
    {
        typedef std::set<boost::weak_ptr<S> > BaseSet;
        typedef BaseSet::const_iterator       BaseIterator;
    
        typedef boost::transform_iterator<
                    make_weak_ptr_const<S>, 
                    BaseIterator
                > iterator;
    
        iterator begin() const 
        {
            return TransformedIterator(data.begin());
        }
    
        iterator end() const
        {
            return TransformedIterator(data.end());
        }
    
        std::set<boost::weak_ptr<S> > data;
    };
    

    If you don't want to use boost::transform_iterator, it is a straightforward task to write your own. I showed how to do this in an answer to another question.