Const strangeness and indirect_iterator generators.

Hi, I've been trying to get indirect_iterator working in what seems (to me) to be a straightforward context -- I have a std::vector of boost::shared_ptr objects, and I need both const and non-const iterators into the vector (I'm using the vector as the sole data member of a container class, and I need the iterators to properly handle const and non-const container types). This looks something like this: class MyClass { // ... }; class MyContainer { public: typedef MyClass value_type; typedef value_type & reference; typedef value_type * pointer; // and so on, for const_reference, const_pointer, etc... // ... private: std::vector<boost::shared_ptr<MyClass> > _data; }; Now, the trouble comes when I attempt to define the iterators for MyContainer using the indirect_iterator generators. If I do the obvious: Approach #1: ------------ typedef indirect_iterator_pair_generator< vector<shared_ptr<MyClass> >::iterator, value_type, reference, const_reference, std::random_access_iterator_tag, pointer, const_pointer>::itgen; typedef typename itgen::iterator my_iterator; typedef typename itgen::const_iterator my_const_iterator; I find that the const_iterator generated is inadequate for use in a container context. Particularly, it produces a my_const_iterator that has the following constructor signature: my_const_iterator(shared_ptr<MyClass> *) Whereas, a const std::vector<shared_ptr<MyClass> > will produce const_iterators that look like this: const shared_ptr<MyClass> * const This causes compilation problems, because inevitably, in this context, you'll want to construct a my_const_iterator from a vector::const_iterator. The problem seems obvious: the indirect_iterator_pair_generator class is considering only non-const base iterators. This led me to try the following: Approach #2: ----------- typedef typename indirect_iterator_generator <typename vector<shared_ptr<MyClass> >::iterator, value_type, reference, pointer, std::random_access_iterator_tag>::type my_iterator; typedef typename indirect_iterator_generator <typename vector<shared_ptr<MyClass> >::const_iterator, value_type, const_reference, const_pointer, std::random_access_iterator_tag>::type my_const_iterator; It seemed that this would solve the problem by independently generating the two types of iterators that are needed (note how I've made the base iterator type ::iterator in one, and ::const_iterator in the other). However, with this method I always obtain compilation errors -- whereever there is a use of the operator->(), the following error is produced (g++ 3.0.3 and 3.2 do the same thing, Linux and Mac OSX): "result of `operator->()' yields non-pointer result" I have yet to figure out what is causing this error. This led me to attempt the following "solution" to the problem: Approach #3: ----------- typedef indirect_iterator_pair_generator <typename vector<shared_ptr<MyClass> >::iterator, value_type,reference,const_reference, std::random_access_iterator_tag, pointer,const_pointer> itgen; typedef typename itgen::iterator my_iterator; typedef indirect_iterator_pair_generator <typename vector<shared_ptr<MyClass> >::const_iterator, value_type,reference,const_reference, std::random_access_iterator_tag, pointer,const_pointer> itgen2; typedef typename itgen2::const_iterator my_const_iterator; This actually works! I can't explain why -- it seems like indirect_iterator_pair_generator and indirect_iterator_generator should behave identically when their template parameters are identical.... The way I see it, there's a bug in at least one of the indirect_iterator generator objects. At the very least, indirect_iterator_pair_generator and indirect_iterator_generator are behaving differently when their parameter types are the same (compare approaches #2 and #3). But there's also the issue of why approach #1 didn't work to begin with -- it *seems* like indirect_iterator_pair_generator should produce a const_iterator type that can be initialized with an iterator from a const vector. This isn't the case. If anyone can explain this to me, and convince me that I'm not going insane, I'd appreciate it greatly ;-) (Standard bug-report disclaimers: Current boost distribution, g++ 3.0.x/3.2.x, both Mac OSX and Linux exhibit identical behaviour.) -Tim

Tim Robertson <timr@u.washington.edu> writes:
Hi,
I've been trying to get indirect_iterator working in what seems (to me) to be a straightforward context -- I have a std::vector of boost::shared_ptr objects
Doesn't work; we know about it. There's a new version of iterator_adaptors in the Boost CVS which fixes this problem. The interface is different, but you're best off using the new one anyway because the old one will expire with the next Boost release.
and I need both const and non-const iterators into the vector (I'm using the vector as the sole data member of a container class, and I need the iterators to properly handle const and non-const container types).
Whether or not this will work depends on what you mean by "correctly".
This looks something like this:
class MyClass { // ... };
class MyContainer { public: typedef MyClass value_type; typedef value_type & reference; typedef value_type * pointer; // and so on, for const_reference, const_pointer, etc...
// ...
private: std::vector<boost::shared_ptr<MyClass> > _data; };
Now, the trouble comes when I attempt to define the iterators for MyContainer using the indirect_iterator generators. If I do the obvious:
Approach #1: ------------
typedef indirect_iterator_pair_generator< vector<shared_ptr<MyClass> >::iterator, value_type, reference, const_reference, std::random_access_iterator_tag, pointer, const_pointer>::itgen;
typedef typename itgen::iterator my_iterator; typedef typename itgen::const_iterator my_const_iterator;
I find that the const_iterator generated is inadequate for use in a container context. Particularly, it produces a my_const_iterator that has the following constructor signature:
my_const_iterator(shared_ptr<MyClass> *)
Whereas, a const std::vector<shared_ptr<MyClass> > will produce const_iterators that look like this:
const shared_ptr<MyClass> * const
No, the last const cannot be part of the type of any const_iterator, because then it wouldn't be incrementable. Also, vector iterators need not be pointers, but that may not be important to your problem.
This causes compilation problems, because inevitably, in this context, you'll want to construct a my_const_iterator from a vector::const_iterator.
The problem seems obvious: the indirect_iterator_pair_generator class is considering only non-const base iterators.
Please try the CVS iterator adaptors and get back to us. -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (2)
-
David Abrahams
-
Tim Robertson