Topic: Proposed change to iterator requirements


Author: kanze@gabi-soft.de (James Kanze)
Date: Fri, 18 Oct 2002 18:05:12 CST
Raw View
Kevin_VanHorn@ndsu.nodak.edu (Kevin S. Van Horn) wrote in message
news:<a2872e97.0210170703.1d389a52@posting.google.com>...
> Anthony Williams pointed out on the Boost developer's list some subtle
> bugs in typical Standard Library implementations.  Consider, for
> example, find_if:

> template <typename InputIterator, typename Predicate>
> InputIterator find_if(InputIterator first, InputIterator last,
> Predicate pred)
> {
>   while (first != last && !pred(*first))
>     ++first;
>   return first;
> }

> The above code is a typical implementation of find_if, found in more
> than one implementation of the Standard Library.  It's also wrong:
> first != last is not required to return a bool; it is only required to
> return a value convertible to bool.  Suppose that it returns the type
> fake_bool, for which we have defined

>   bool operator&&(fake_bool, bool) { return false; }

Even the more reasonable:

    bool operator&&(fake_bool lhs, bool rhs)
    {
        return static_cast< bool >(lhs) && rhs ) ;
    }

will cause problems, since pred(*first) will be evaluated even if
first==last.

> Then find_if will not work as required.

> This example makes me think that everywhere the standard requires
> "convertible to bool", it should instead require "integer type".

Or pointer type?  Personally, I can see no reason for an operator== to
return anything but a bool, but if you are going to allow integer types,
you should probably also allow pointers.  And maybe floating point, or
user defined types which convert to bool.  The latter is, in fact,
probably the only possibly useful liberty; one can imagine some sort of
template expressions which evaluate the expression lazily.

IMHO, the "correct" solution would be to not allow overloading || and
&&, but it is doubtlessly too late for that now.  Alternatively we can
either specify that behavior is undefined in the presence of an
overloaded &&, ! or || on the return type, or we can require the
implementations to conform (e.g. by enclosing the == expression in a
static_cast to bool).

> On a similar vein, it seems to me that the requirement "convertible to
> T" for the value of the expression "*it", where T is the value type of
> the input iterator it, would be better as "T, T const, T &, or T const
> &".  I can think of no conceivable advantage from allowing the
> dereference operator return a value of a type U other than the value
> type, and the possibility of subtle bugs from running into a function
> overloaded on T and U seems a significant disadvantage.

The use of proxies is a common technique.  The fact that it is already
somewhat limited (because &*t must result in a real address) is a pain.
No need to make it worse.

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Kevin_VanHorn@ndsu.nodak.edu (Kevin S. Van Horn)
Date: Sat, 19 Oct 2002 19:52:11 +0000 (UTC)
Raw View
James Kanze wrote:

> > On a similar vein, it seems to me that the requirement "convertible to
> > T" for the value of the expression "*it", where T is the value type of
> > the input iterator it, would be better as "T, T const, T &, or T const
> > &".  I can think of no conceivable advantage from allowing the
> > dereference operator return a value of a type U other than the value
> > type, and the possibility of subtle bugs from running into a function
> > overloaded on T and U seems a significant disadvantage.
>
> The use of proxies is a common technique.

I'm familiar with using this technique for post-increment, but not for
the dereference operator.  Can you give me an example of the latter?

>  The fact that it is already
> somewhat limited (because &*t must result in a real address) is a pain.

I don't follow you.  We're talking input iterators here, which don't
have to return lvalues. The elements of the sequence may very well be
dynamically generated, so &*i looks a bit pointless to me, as you may
just be getting the address of a temporary.

BTW, &*i isn't correct even for a forward iterator in a generic
context, because of possible overloading of operator&(); you need to
write something like boost::addressof(*i).

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: andys@evo6.com.NoSpam (Andy Sawyer)
Date: Sat, 19 Oct 2002 20:56:14 +0000 (UTC)
Raw View
In article <a2872e97.0210190505.638da6bf@posting.google.com>,
 on Sat, 19 Oct 2002 19:52:11 +0000 (UTC),
 Kevin_VanHorn@ndsu.nodak.edu (Kevin S. Van Horn) wrote:

> James Kanze wrote:
>
> > > On a similar vein, it seems to me that the requirement "convertible to
> > > T" for the value of the expression "*it", where T is the value type of
> > > the input iterator it, would be better as "T, T const, T &, or T const
> > > &".  I can think of no conceivable advantage from allowing the
> > > dereference operator return a value of a type U other than the value
> > > type, and the possibility of subtle bugs from running into a function
> > > overloaded on T and U seems a significant disadvantage.
> >
> > The use of proxies is a common technique.
>
> I'm familiar with using this technique for post-increment, but not for
> the dereference operator.  Can you give me an example of the latter?

Well, it's one example of the broken-ness of the evil
std::vector<bool>. See std::vector<bool>::iterator and
std::vector<bool>::reference for the gory details.

Regards,
 Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
 how fast light travels it finds the darkness has always got there first,
 and is waiting for it."                  -- Terry Pratchett, Reaper Man

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Kevin_VanHorn@ndsu.nodak.edu (Kevin S. Van Horn)
Date: Thu, 17 Oct 2002 17:26:27 +0000 (UTC)
Raw View
Anthony Williams pointed out on the Boost developer's list some subtle
bugs in typical Standard Library implementations.  Consider, for
example, find_if:

template <typename InputIterator, typename Predicate>
InputIterator find_if(InputIterator first, InputIterator last,
Predicate pred)
{
  while (first != last && !pred(*first))
    ++first;
  return first;
}

The above code is a typical implementation of find_if, found in more
than one implementation of the Standard Library.  It's also wrong:
first != last is not required to return a bool; it is only required to
return a value convertible to bool.  Suppose that it returns the type
fake_bool, for which we have defined

  bool operator&&(fake_bool, bool) { return false; }

Then find_if will not work as required.

This example makes me think that everywhere the standard requires
"convertible to bool", it should instead require "integer type".

On a similar vein, it seems to me that the requirement "convertible to
T" for the value of the expression "*it", where T is the value type of
the input iterator it, would be better as "T, T const, T &, or T const
&".  I can think of  no conceivable advantage from allowing the
dereference operator return a value of a type U other than the value
type, and the possibility of subtle bugs from running into a function
overloaded on T and U seems a significant disadvantage.

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]