[ptr_container] Const & non-const ptr_map iteration over mapped values.
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
Rodolfo Federico Gamarra skrev:
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; } };
I would just implement this as (abbreviated) template< class R > struct X { template< class Pair > R operator()( const Pair& 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).
Well, why do you want to define that typedef, when it is easier to infer the type automatically?
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?
Why? Dont map::value_type v = *m.find(x) work?
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.
Again, why do you want to do this? -Thorsten
participants (2)
-
Rodolfo Federico Gamarra
-
Thorsten Ottosen