2013/4/30 Jeffrey Lee Hellrung, Jr.
On Mon, Apr 29, 2013 at 10:54 AM, TONGARI
wrote: 2013/4/30 Jeffrey Lee Hellrung, Jr.
On Sun, Apr 28, 2013 at 6:38 AM, Philipp Moeller < philipp.moeller@geometryfactory.com> wrote:
TONGARI
writes: Hi folks,
I wonder if there's a general const_iterator adaptor that transforms any iterator to a const one:
template<class Iterator> struct const_iterator : iterator_adaptor < const_iterator<Iterator>, Iterator , typename iterator_value<Iterator>::type const > { const_iterator() {}
const_iterator(Iterator const& base) : const_iterator::iterator_adaptor_(base) {} };
Which is simple but handy for use in that we don't have to make 2 versions for both const & non-const iterators each time we make a container.
Does Boost offer this which I missed somewhere, or would you think it's a good idea to add?
If you look at the documentation of iterator_facade you will see that it already shows how to just write one version of the iterator and get a const version for free: pass a `const T` as the second argument of iterator_face and it should work.
I think this is typically essentially what you want to do. Define a helper template like
template< class T > struct iterator_helper { typedef /*...*/ type; };
then
typedef iterator_helper< value_type >::type iterator; typedef iterator_helper< value_type const >::type const_iterator;
If that isn't possible or convenient, your iterator and const_iterator are probably sufficiently different that defining them separately will be acceptable.
I still think this is preferable.
The typical problem with your const_iterator adaptor above is that it
likely can't be constructed in a const context, since you wouldn't be able to obtain an (mutating) iterator (unless you do const_cast contortions).
True, that's what I did exactly (i.e. const_cast).
Also, shouldn't the reference type passed to iterator_adaptor also need to be "constified"? Which gets complicated when the reference type is a proxy reference...
Haven't considered that, so the non-intrusive const_iterator may not be general enough, but what I looked for was something that works for most cases.
We could have that for our 'detail' usage, but if it's common enough, then it might be nice to have it in public.
So would you suggest such an adaptor for those simple cases no more than adding the const?
A utility that only works for simple cases inevitably evolves and complicates to handle the more complex cases as feature requests come through :/ And, like I hinted at above, I don't think it can be made to work with proxy references without adding a hook to "constify" the proxy reference. I'm not sure the complication justifies its existence. There's also mild safety issues, in that calling base() on the const_iterator gives you the underlying (mutating) iterator.
So I would hesitate to add this myself under the Iterator library, but, hey, maybe you can convince someone else :)
Maybe the discussion would facilitated by providing a concrete use case, as, in my experience, I haven't been compelled to create such an adaptor.
I started to think if we can have a type trait like 'constify' which allows users to specialize for their types.