Boost logo

Boost Users :

Subject: [Boost-users] [ptr_container] Const & non-const ptr_map iteration over mapped values.
From: Rodolfo Federico Gamarra (rgamarra_at_[hidden])
Date: 2009-06-14 12:23:59


Hi all!!

In my class have an internal member of type

typedef boost::ptr_map<int, Component> InternalComponentCollection;

I'd like to provide const and non-const iterators, through appropriate
two pairs of begin / end methods, in order to have "const Component&"
and "Component&" as return type in each of the dereferencing
operators. What's the way to do that?

What I tried:

Since the underlying storage relies in "pair" with a pointer, I
thought of using a transform iterator to project "second" and then
dereference the pointer; something like, for instance,

ComponentIterator Begin() {
  return boost::make_transform_iterator(fComponents.begin(), fResolver);
}

where fResolver is an instance of

template<class T1, class T2, class R>
struct SecondResolver {
  typedef R result_type;
  template< template <typename,typename> class Pair>
  result_type operator()(const Pair<T1, const T2>& p) const {
    return * p.second;
  }
};

and having

typedef SecondResolver<KeyType, MappedType, MappedReference> ComponentResolver;
typedef typename InternalComponentCollection::key_type KeyType;
typedef typename InternalComponentCollection::mapped_type MappedType;
typedef typename InternalComponentCollection::mapped_reference MappedReference;
typedef typename InternalComponentCollection::iterator PairIterator;
typedef boost::transform_iterator<ComponentResolver, PairIterator>
ComponentIterator;

The case for const iteration is similarly implemented, using the
following typedefs:

typedef SecondResolver<KeyType, ConstMappedType, ConstMappedReference>
  ConstComponentResolver;
typedef const Component* /* No nested typedef for this...*/ ConstMappedType;
typedef typename InternalComponentCollection::const_mapped_reference
  ConstMappedReference;
typedef typename InternalComponentCollection::const_iterato PairConstIterator;
typedef boost::transform_iterator<ConstComponentResolver, PairConstIterator>
  ComponentConstIterator;

My remarks about my solution are:

1) SecondResolver is not an "UnaryFunction" in the sense of the C++
standard, since there's no "argument_type" nested typedef. Tough it
seems that that isn't actually required by transform_iterator. I have
problems in trying to define that typedef (see 2).

2) The actual pairs are instances of

boost::ptr_container_detail::ref_pair

so it wouldn't be right to typedef that as arg type (it's a "detail").
This class provides implicit conversion from std::pair, but no
implicit conversion to std::pair. So that's why I wrote the operator()
as a template function, since cannot give the operator an explicit
type: nor ref_pair (being a detail), nor std::pair (not having the
conversion). Should that conversion be provided?

3) I wrote ConstMappedType typedef explicitly, without relying in a
nested typedef in the original class. Doing

typedef const MappedType ConstMappedType;

doesn't work because the const binds to the pointer, not to the pointed type.

Other possibility I looked was to have instead (for the const case,
the other one is similar):

typedef typename InternalComponentCollection::const_reference ConstReference;
typedef SecondResolver2<ConstMappedReference, ConstReference>
  ConstComponentResolver;

template<class RetType, class ArgType>
  struct SecondResolver2 {
    typedef RetType result_type;
    typedef ArgType argument_type;
    result_type operator()(argument_type p) const {
      return * p.second;
    }
};

Anyone is better?

Thanks a lot in advance.

--
Rodolfo Federico Gamarra

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net