Рассмотрим эту простую пару шаблонов функций.
template <typename T>
void foo(T& ) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
template <typename C>
void foo(const C& ) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
Если мы назовем foo аргументом non-const:
int i = 4;
foo(i);
Перегрузка T& предпочтительнее на основе [over.ics.rank]/3.2.6, так как выведенная ссылка int& меньше CV, чем выведенная ссылка const int&.
Однако, если мы назовем foo аргументом const:
const int ci = 42;
foo(ci);
Перегрузка const C& предпочтительнее, потому что она "более специализирована" на основе [over.match.best]/1.7. Но каковы правила для определения этого? Я понял, что вы синтезируете тип для C (назовите его M) и попытайтесь выполнить вывод на foo(M) - но это будет успешным (с T == M). Это только значение r, которое приведет к отказу вывода, но как компилятор знает, что ему нужно выбрать rvalue на этапе синтеза?