Рассмотрим эту простую пару шаблонов функций.
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 на этапе синтеза?