Subject: Re: [boost] [iterator] [property_map] Enhancement proposals
From: Louis Dionne (louis.dionne92_at_[hidden])
Date: 2012-10-13 19:25:51


Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung <at> gmail.com> writes:

> > Accepting any iterator that is convertible to the wrapped iterator is nice
> > if it is not dangerous because it allows to do this:
> >
> > typedef chained_output_iterator<Functor1,
> > chained_output_iterator<Functor2,
> > std::back_insert_iterator<std::vector<T>>>> OutIter;
> > // Then, if Functor1 and Functor2 are default constructible:
> > std::vector<T> vec;
> > OutIter result(std::back_inserter(vec));
> >
> > If the constructor only takes an instance of the wrapped iterator, the
> > following must be done, which could be annoying if one creates a long
> > chain:
> >
> > typedef chained_output_iterator<Functor2,
> > std::back_insert_iterator<std::vector<T>>> Chain;
> > typedef chained_output_iterator<Functor1, Chain> OutIter;
> > std::vector<T> vec;
> > OutIter result(Chain(std::back_inserter(vec)));
> >
> > So I would advocate in favor of keeping the initial implementation for the
> > first two constructors, unless I am missing something.
> >
>
> Wouldn't the first block of code above not compile regardless of whether
> the unary constructor is a template constrained by enable_if<
> is_convertible > or takes the wrapped iterator directly? The result of
> std::back_inserter(vec) is not convertible to the intermediate
> chained_output_iterator in either case.

Yes, the first block of code compiles. Let's say we have:

    typedef std::back_insert_iterator<std::vector<T> > Third;
    typedef chained_output_iterator<Functor2, Third> Second;
    typedef chained_output_iterator<Functor1, Second> First;

Third is convertible to Second:

    template <typename Iterator>
    Second(Iterator const& iterator,
           typename enable_if_convertible<Iterator, WrappedIter>::type* =0);

with [Iterator = Third]
     [WrappedIter = Third] (because Second::WrappedIter == Third)

By the same mechanism, Second is convertible to First. Now, let's see why we
can construct a First from a Third:

    Third third;
    First first(third); // This calls the template unary constructor below.

    First(Third const& iterator,
          typename enable_if_convertible<Third, Second>::type* =0)
        : out_(iterator) // This calls the template unary constructor below.
    { }

    Second(Third const& iterator,
           typename enable_if_convertible<Third, Third>::type* = 0)
        : out_(iterator) // This calls the constructor of Third, which is
    { } // std::back_insert_iterator.

I hope my explanation is clear enough. There is also a unit test for this on
the master branch.

> If you had the following chained_output_iterator constructor:
>
> template< class G, class J >
> chained_output_iterator(chained_output_iterator<G,J>,
> typename enable_if_c< mpl::and<
> is_convertible<H,G>,
> is_convertible<J,I>
> >::value >::type * = 0);
>
> Oops, now chained_output_iterator< F, derived_t * > is convertible to
> chained_output_iterator< F, base_t * >. is_convertible<J,I> is too loose
> (admittedly, there are many iterator contexts where you simply cannot
> prevent the derived_t * -> base_t * conversion, but if you can prevent it,
> you should).
>
> Presently, there is no such converting constructor, and I don't yet see a
> need for one.

Thanks for the explanation. I replaced the loose copy constructor by the one
generated by the compiler.

> Best (i.e., least work for me) would be to provide the header, the unit
> test, any patches to the present Boost.Iterator documentation, and a
> contract signed in blood that you'll support this for life. Well, okay,
> I'll take 3 out of 4 :)
>
> Where you make the files available doesn't matter too much, just as long as
> I can easily grab them when ready. I guess the official route is to create
> a feature enhancement request trac ticket with the files attached.

Alright. I'll create a ticket when everything is ready. Since it's not
getting in before at least 1.53, I'll take my time and do something good.

Thanks!

Louis Dionne