In Functional programming in C++, chapter 11 deals with some basic template meta programming.
In this context, the author shows this implementation of remove_reference/remove_reference_t, which are essentially the same as those described on cppreference.
template<typename T> struct remove_reference { using type = T; };
template<typename T> struct remove_reference<T&> { using type = T; };
template<typename T> struct remove_reference<T&&> { using type = T; };
template<typename T> using remove_reference_t = typename remove_reference<T>::type;
With reference to the code above, the author comments that when "calling" remove_reference_t<int>, only the general (or primary? What is the correcto word here?) template successfully substitutes T, and the other two fail. This is clear to me, there's no way int can be written as/matched against T& or T&&.
As regards remove_reference_t<int&>, however, the author says that the second specialization cannot match. Well, couldn't it be a match thanks to reference collapsing? I mean, can't T&& match int& if I substitute T for int&, thus getting int&&& == int&?
Similarly, when calling (Why in the world did I think that remove_reference_t<int&&>, can't the first specialization's T& match int&& if T is substituted for int&?& & would collapse to && instead of &?)
What makes the compiler discard one specialization?