|
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