Topic: Iterator concepts (was: Defect Report: istreambuf_iterator should have an operator->())


Author: tasjaevan@gmail.com
Date: Wed, 28 Mar 2007 09:39:46 CST
Raw View
On Mar 27, 9:53 pm, "Douglas Gregor" <doug.gre...@gmail.com> wrote:
> On Mar 26, 1:56 pm, tasjae...@gmail.com wrote:
>
> > In that terminology, istreambuf_iterator is only 'Readable', not
> > 'Readable Lvalue'.
>
> The iterator concept refactoring in N1477 is still a good idea, even
> though it wasn't the best fit for TR1.
> We're planning to bring those iterator concepts into C++0x (providing
> backward compatibility for C++98 iterators the same way we do now,
> with concept maps).
>

That's excellent news! How is that going? So far, I've seen N2083,
which specifies C++98 iterator concepts (plus mutable versions of
those).

> > If we were switching to those concepts, I would have suggested
> > operator-> return a proxy (much like boost::iterator_facade does for
> > non-lvalue iterators).
>
> One can still have proxies with Input Iterators.
>
> > As it is, am I right in thinking that returning a proxy would clash
> > with the concepts library proposal?
>
> They should not clash; if they do, it's an error in our specification
> of the concepts (or in ConceptGCC's handling of those concepts). The
> "pointer" and "reference" associated types of an Input Iterator are
> permitted to be proxies.
>

It's good that there's no clash. It was just a gut feeling that there
might be problems.

I worry that specifying 'pointer' and 'reference' to be proxies is a
little sneaky, and I believe there is a more direct solution using the
N1477 concepts.

(Apologies if I've messed up the concept syntax, and I've only put the
immediately relevant bits in)

  concept ReadableIteratorAccess<X> : IteratorAssociatedTypes<X>
  {
    typename _unspecified_arrow_return_type;
    typename _unspecified_deref_return_type;

    where Convertible<_unspecified_deref_return_type, value_type>;

    _unspecified_arrow_return_type X::operator->() const;
    _unspecified_deref_return_type X::operator*() const;
  }

  concept ReadableLvalueIteratorAccess<X> : ReadableIteratorAccess<X>
  {
    typename _unspecified_arrow_return_type = value_type*;
    typename _unspecified_deref_return_type = value_type&;
  }

The _unspecified_arrow_return_type is meant to have an operator-> that
eventually results in a value_type* (possibly through a chain of
operator->s). I don't know if that can be specified.

The point is to allow iterators' operator* to return by value (or
return a proxy), but the return types of * and -> can be relied on to
be value_type& and value_type* for lvalue iterators (the most common).
I don't think the 'reference' and 'pointer' tags are needed.


James


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Wed, 28 Mar 2007 12:31:54 CST
Raw View
On Mar 28, 11:39 am, tasjae...@gmail.com wrote:
> I worry that specifying 'pointer' and 'reference' to be proxies is a
> little sneaky, and I believe there is a more direct solution using the
> N1477 concepts.
>
> (Apologies if I've messed up the concept syntax, and I've only put the
> immediately relevant bits in)
>
>   concept ReadableIteratorAccess<X> : IteratorAssociatedTypes<X>
>   {
>     typename _unspecified_arrow_return_type;
>     typename _unspecified_deref_return_type;
>
>     where Convertible<_unspecified_deref_return_type, value_type>;
>
>     _unspecified_arrow_return_type X::operator->() const;
>     _unspecified_deref_return_type X::operator*() const;
>   }

This is almost precisely how InputIterator is specified with concepts
today, except that _unspecified_arrow_return_type is called "pointer"
and _unspecified_deref_return_type is called "reference".

>   concept ReadableLvalueIteratorAccess<X> : ReadableIteratorAccess<X>
>   {
>     typename _unspecified_arrow_return_type = value_type*;
>     typename _unspecified_deref_return_type = value_type&;
>   }

You'll need a SameType requirement here, not new associated types.
Instead of those two "typename" declarations in the body, use:

  requires SameType<_unspecified_arrow_return_type, value_type*>,
              SameType<_unspecified_deref_return_type, value_type&>;

(The "requires" keyword has replaced the "where" keyword.)

We currently do this in the MutableForwardIterator concept.

> The _unspecified_arrow_return_type is meant to have an operator-> that
> eventually results in a value_type* (possibly through a chain of
> operator->s). I don't know if that can be specified.

Sure.

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: tasjaevan@gmail.com
Date: Thu, 29 Mar 2007 11:04:49 CST
Raw View
On Mar 28, 7:31 pm, "Douglas Gregor" <doug.gre...@gmail.com> wrote:
>
> This is almost precisely how InputIterator is specified with concepts
> today, except that _unspecified_arrow_return_type is called "pointer"
> and _unspecified_deref_return_type is called "reference".
>

Ah yes, I see that now. All it boils down to is that reference should
be value_type& for lvalue iterators (and likewise for pointer) ...

> >   concept ReadableLvalueIteratorAccess<X> : ReadableIteratorAccess<X>
> >   {
> >     typename _unspecified_arrow_return_type = value_type*;
> >     typename _unspecified_deref_return_type = value_type&;
> >   }
>
> You'll need a SameType requirement here, not new associated types.
> Instead of those two "typename" declarations in the body, use:
>
>   requires SameType<_unspecified_arrow_return_type, value_type*>,
>               SameType<_unspecified_deref_return_type, value_type&>;
>
> (The "requires" keyword has replaced the "where" keyword.)
>
> We currently do this in the MutableForwardIterator concept.
>

. and that's what I missed. Thanks.

It's clear a massive amount of work has gone into the library
concepts, quite apart from the concepts proposal itself. I think it's
a hugely significant contribution to C++.

Just two more questions arising from the iterator doc:

  1) Is there any difference between Convertible<X, Y> and
Convertible<X, const Y&>?
  2) For the operator* return type of non-mutable lvalue iterators,
would SameType<value_type&, remove_const<reference>::type> fit the
refinement hierarchy (rather than using Convertible)? (I'm wondering
if that specifies it more accurately)


James


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: tasjaevan@gmail.com
Date: Thu, 29 Mar 2007 15:36:37 CST
Raw View
On Mar 29, 6:04 pm, tasjae...@gmail.com wrote:
>   2) For the operator* return type of non-mutable lvalue iterators,
> would SameType<value_type&, remove_const<reference>::type> fit the
> refinement hierarchy (rather than using Convertible)? (I'm wondering
> if that specifies it more accurately)
>

Sorry, I meant

  SameType<value_type,
remove_const<remove_reference<reference>::type>::type>

I hope I got the idea across, even so


James

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Sun, 1 Apr 2007 14:38:34 CST
Raw View
On Mar 29, 1:04 pm, tasjae...@gmail.com wrote:
> Just two more questions arising from the iterator doc:
>
>   1) Is there any difference between Convertible<X, Y> and
> Convertible<X, const Y&>?

Ah, very good question. Ideally, we want the latter to mean, "X is
convertible to a reference to a const lvalue". However, I don't
believe the two are currently distinguishable in the language.

>   2) For the operator* return type of non-mutable lvalue iterators,
> would SameType<value_type&, remove_const<reference>::type> fit the
> refinement hierarchy (rather than using Convertible)? (I'm wondering
> if that specifies it more accurately)

It would, but traits do not work within concepts. Traits work by
selecting different results from one instantiation to another, while
concepts work by expressing the commonality among all instantiations.

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]