
Rob Stewart <stewart@sig.com> 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