Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2005-09-17 00:38:50


Rob Stewart <stewart_at_[hidden]> writes:

> I've been thinking about this issue and wonder if the following
> wouldn't solve the problem neatly for both conforming and
> non-conforming compilers:
>
> // whatever/foo.h
> namespace whatever
> {
> class foo
> {
> ...
> };
>
> // for conforming compilers
> unspecified begin(foo const &) { ... };
> ...
> }
>
> // for non-conforming compilers
> namespace boost { namespace range {
> using whatever::begin;
> } }
>
> // boost/range/begin.hpp
> namespace boost
> {
> inline template <T>
> unspecified begin(T const & range_i)
> {
> using boost::range::begin;
> return begin(range_i);
> }
> }

Careful. Many of the problems you can run into with dispatching only
show up in the case where the definition of begin you want to be
selected *follows* the template that uses it.

> If the author of foo has no other need for begin(), then
> whatever/foo.h could be done like this instead:
>
> // whatever/foo.h
> namespace whatever
> {
> class foo
> {
> ...
> };
> }
>
> namespace boost { namespace range {
> unspecified begin(foo const &) { ... };
> } }

No it can't. That begin() will only be found by ordinary lookup,
looks *backwards* from the point of definition of the template in
which it is used. That's the problem I referred to above.

> If whatever::foo belongs to a user of Boost.Range that only uses
> conforming compilers, then foo.h only needs to be:
>
> // whatever/foo.h
> namespace whatever
> {
> class foo
> {
> ...
> };
>
> unspecified begin(foo const &) { ... };
> ...
> }
>
> If whatever::foo provides get_begin() instead, for whatever
> reason, then foo.h becomes:
>
> // whatever/foo.h
> namespace whatever
> {
> class foo
> {
> ...
> };
>
> unspecified get_begin(foo const &) { ... };
> ...
> }
>
> namespace boost { namespace range {
> inline unspecified begin(foo const & foo_i)
> {
> return get_begin(foo_i);
> }
> } }

Once again, no, for the same reason cited above.

> This approach provides a number of benefits:
>
> - we can use the most obvious name, boost::range::begin, for the
> point of customization
> - benefits from ADL when supported
> - Types in namespace std or built-in types (pointers) can be
> retrofitted in boost::range and will work like everything else
> (though you must include the appropriate header to get the
> required boost::range::begin() overload)
> - flexibility for those wishing to support Boost.Range
> - non-conformance code can be excised easily later
>
> Did I miss something?

Two-phase name lookup.

  14.6.4 Dependent name resolution [temp.dep.res]

    In resolving dependent names, names from the following sources are
    considered:

    â€” Declarations that are visible at the point of definition of the
      template.

    â€” Declarations from namespaces associated with the types of the
      function arguments both from the instantiation context
      (14.6.4.1) and from the definition context.

Unless you arrange for boost::range to be an associated namespace of
foo, you're setting up dangerous #include order dependencies.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk