OK in four different test cases. In all cases, the conversion sequences are all the same - no conversions are required, so we need to move on to the next step of overload resolution.
foo(wt, i);
There are two potential overloads here. All and Hrg<true>
template <class Hrm, class A> void foo(Hrm& h, A& a); template <template <bool> class Hrg> void foo(Hrg<true>& h, const int& a);
In [over.ics.rank] we have (thanks @dyp):
The standard conversion sequence S1 is a better conversion sequence than the standard conversion sequence S2 if ... - S1 and S2 are the binding bindings (8.5.3), and the types to which the links refer are the same type, except for the top-level cv qualifiers , and the type to which the link referenced, initialized by the S2 sign, is more qualified than the type to which the link initialized by the S1 sign refers.
const int larger than CV than int , so int overloading is preferred - which will be shared.
foo(wf, i);
There are two overloads here:
template <class Hrm, class A> void foo(Hrm& h, A& a) template <template <bool> class Hrg> void foo(Hrg<false>& h, int& a)
Both conversion sequences are the same here, so nothing in this section can distinguish one from the other. So, we go to [over.match.best]:
Given these definitions, a viable function F1 is defined as a better function than another viable function F2 if for all arguments i, ICSi ( F1 ) is no worse than the transformation scheme than ICSi ( F2 ), and then ...
- F1 and F2 are specialized function templates, and the function template for F1 is more specialized than the template for F2 in accordance with the partial ordering rules described in 14.5.6.2.
The rules for "more specialized than" are complex, but basically mean that the second overload is viable for a strict subset of the types for which the first is viable, so it is preferred.
foo(wt, ri);
Here we have the same two overloads as in the first case:
template <class Hrm, class A> void foo(Hrm& h, A& a); template <template <bool> class Hrg> void foo(Hrg<true>& h, const int& a);
The conversion sequences are identical, but the second overload is more specialized than the first; therefore, specialized overload is preferable for the same reasons as in (2).
foo(wf, ri);
Here, "general" congestion is the only viable congestion.
UPDATE . The new tests you added are simpler than the previous four. Given two foo overloads:
template <class Hrg> void foo(Hrg& h, int& a); template <class Hrg> void foo(Hrg& h, const int& a);
When called with ri only the second overload is possible. But when called with i , the first overload is preferred for the same reasons as (1) above - int less than cv-qual than const int .