The key, as you correctly imagined, is that it is a template and that the argument type is being deduced. When you call Test
with an lvalue, the rules for argument type deduction when the argument is an rvalue-reference will deduce the type T
to be an lvalue-reference, and thus the specialization becomes:
template <>
void Test<int&>(int & && arg)
At this point the reference collapsing rules kick in and the type of the argument becomes:
template <>
void Test<int&>(int & arg)
While the template takes an rvalue-reference, if the type is an lvalue-reference the argument becomes an lvalue-reference itself.