From: Anthony Williams (anthony_w.geo_at_[hidden])
Date: 2005-05-12 03:56:02
"Thorsten Ottosen" <nesotto_at_[hidden]> writes:
> "Anthony Williams" <anthony_w.geo_at_[hidden]> wrote in message
> | "Thorsten Ottosen" <nesotto_at_[hidden]> writes:
> | > | > in what way is it fragile?
> | > |
> | > | The meaning of the language construct for( type i: expr ) changes based
> | > | what overloads are visible. This is relatively uncommon for C++.
> | >
> | > the meaning of
> | >
> | > for( const auto& r : make_range( expr ) )
> | >
> | > would also change depending on what overloads that are visible.
> | >
> | > so I'm still not getting what "fragile" means.
> | If you explicitly say make_range(expr), then you're explicitly calling a
> | function, so it's obvious that if you include headers that define overloads
> | that function, the behaviour may change. If you really really want to ensure
> | particular overload is called, you can, with some combination of
> | and casting.
> my point was that this "fragility" is all over the place in C++.
Yes, and we do what we can to avoid it. Introducing an instance into the core
of the language seems to be asking for trouble.
> | If the "for(:)" construct calls free functions directly then you have no
> | control over which overload is selected, except by carefully choosing which
> | headers get included. If you need a header which changes the overload set in
> | bad way, you're stuck.
> you make it sound like ADL is a horrible thing :-)
It can be. Introducing ADL needs to be done carefully and with much
thought. begin and end are common words, and there may be overloads in scope
which are nothing to do with iterating. Actually, come to think of it, if I am
iterating over a range, I sometimes use *variables* called begin and end to
mark the ends of the range, which would completely scew up ADL:
void some_algorithm(SomeIterator begin,SomeIterator end)
// do stuff. Can't do anything which relies on calling begin() or end()
// with ADL, as variables will be found first.
Likewise, within a member function of a container that itself implements
begin() and end() functions, the member functions will be found first, and
> I havn't been able to construct realistic examples that shows your dreadful
> scenario, but
> I won't mind seeing them.
> | If the contents of the headers varies by platform
> | (e.g. standard headers don't specify which other standard headers they pull
> | in), then the code may work on one platform and not on another, *and there's
> | not a lot you can do about it*.
> well, that's a problem already today. <std> is the way to go.
In current cases where it happens, you can generally modify the call site to
ensure that the correct overload is called. If you can't access the call site,
because it is generated by the compiler, then you can't fix it. Note that the
problem is not that of required headers not being included, but rather that of
not-wanted headers being included.
> | Also, the use of free functions implies that at least one header *has* to be
> | included, even to use the construct with arrays, which just feels wrong.
> we're trying to get rid of arrays, so it might even be a good idea. if it
> doesn't compiles.
Who is "we"? There are many valid uses of arrays, not least of which for
fixed-content tables, which is precisely one scenario where I might wish to
use for(:) to iterate over the contents.
Requiring the include of a header to use one core language feature with
another is just plain wrong.
-- Anthony Williams Software Developer
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk