Both reference binding and an lvalue-to-rvalue conversion are given an exact match rank:
§ 13.3.3.1.4 [over.ics.ref]/p1:
When a parameter of reference type binds directly (8.5.3) to an argument expression, the implicit conversion sequence is the identity conversion.
Thus, the compiler can't choose between the two on the basis of better conversion sequence selection, and tries to partially order the two overloads of exp
(because the more specialized function templates take precedence in overload resolution). However:
§ 14.8.2.4 [temp.deduct.partial]/p5:
Before the partial ordering is done, certain transformations are performed on the types used for partial ordering:
— If P
is a reference type, P
is replaced by the type referred to.
— If A
is a reference type, A
is replaced by the type referred to.
This makes the two overloads indistinguishable, since neither is more specialized, as from the partial ordering point of view they look the same, and no other exception applies.
If your primary goal is to have one overload for rvalues and another for lvalues, you can define them as follows:
template <typename T>
void exp(T&& a, T&& b) {}
template <typename T>
void exp(T& a, T& b) {}
Now, although exp(T&& a, T&& b)
is viable for lvalues as well, the other overload is deemed more specialized:
§ 14.8.2.4 [temp.deduct.partial]/p9:
If, for a given type, deduction succeeds in both directions (i.e., the types are identical after the transformations above) and both P
and A
were reference types (before being replaced with the type referred to above):
— if the type from the argument template was an lvalue reference and the type from the parameter
template was not, the argument type is considered to be more specialized than the other; otherwise [...]
which makes exp(T& a, T& b)
to be the preffered one for lvalues, and exp(T&& a, T&& b)
the only viable for rvalues in turn.
DEMO