You obviously need the const &
version because otherwise your range_begin
would be uncallable for const-qualified objects.
Less obvious is why you also need the &
version, but it's simple: if you don't provide it, then your custom function is a worse match than Boost's own version.
Here's a short non-Boost example:
namespace M {
struct S { };
void f(const S &);
}
namespace N {
template <typename T>
void f(T &);
template <typename T>
void g(T &t) { f(t); }
}
void h() {
M::S s {};
N::g(s);
}
Here, during instantiation of N::g<M::S>
, an unqualified call f(t)
is made, and the argument t
has type M::S
. There are two candidates: N::f<M::S>
is in the same namespace, but ADL also finds M::f
. The former's parameter is M::S &
. The latter's is const M::S &
. That means the former is a better match, even if you really want the version in namespace M
to be used.
An additional overload M::f(S &)
avoids this problem.