
Dave Abrahams wrote:
First, Michel, thanks for addressing this important matter. 2nd, I'm a wee bit worried about ODR issues. At first it looks like you're saying to define has_begin in namespace boost. Then your code seems to imply it's in namespace range_detail. I think the latter is probably OK, but not the former. The key thing is that the definition of boost::begin should not itself alter the result of has_begin for any given type.
Ah! It's the latter. I should have written as #ifndef BOOST_NO_RANGE_BASED_FOR namespace boost { using std::begin; namespace range_detail { // has_begin metafunction... } template <typename Range> inline typename boost::range_iterator<Range>::type begin(Range& rng, typename disable_if<range_detail::has_begin<Range>>::type* = 0) { return range_begin(rng); } // const version ... } #else // existing code... So don't worry :-) Here is a complete code I added to boost/range/begin.hpp: (And I attached header files (not the patches) in this mail, for convenience.) #ifndef BOOST_NO_RANGE_BASED_FOR #include <boost/mpl/bool.hpp> #include <boost/utility/enable_if.hpp> #include <boost/range/iterator.hpp> namespace boost { using std::begin; namespace range_detail { template <typename T> struct has_begin_impl { typedef char true_type; typedef char false_type[2]; template <typename S> static true_type& check(S* s_ptr, decltype(s_ptr->begin())* = 0); template <typename S> static false_type& check(...); static const bool value = sizeof(check<T>(0)) == sizeof(true_type); }; template <typename T> struct has_begin : boost::mpl::bool_<has_begin_impl<T>::value> {}; } template <typename Range> inline typename boost::range_iterator<Range>::type begin(Range& rng, typename disable_if<range_detail::has_begin<Range>>::type* = 0) { return range_begin(rng); } template <typename Range> inline typename boost::range_iterator<Range const>::type begin(Range const& rng, typename disable_if<range_detail::has_begin<Range>>::type* = 0) { return range_begin(rng); } } #else // existing code... Regards, Michel