Универсальный опорный приоритет vs const?

Когда я рассмотрю две следующие перегрузки:

template <class... T> void f(const T&... x);
template <class T> void f(const T& x);

У меня есть гарантия, что f(x) всегда будет вызывать вторую функцию и никогда не приведет к двусмысленности. В некотором смысле вторая версия является общепринятой по сравнению с первой для одного аргумента независимо от его типа.

Теперь рассмотрим ситуацию, когда существует универсальная ссылка и константные эталонные версии функции:

template <class T> void f(T&& x);
template <class T> void f(const T& x);

Мой вопрос: является ли их универсальным приоритетом между этими двумя функциями независимо от типа x (r-value reference, reference, cv-qualifiers, pointer...), как в предыдущем случае? (и если да, то какой приоритет?)

Ответы

Ответ 1

Между этими двумя функциями нет универсального приоритета. Они одинаково конкурируют в алгоритме разрешения перегрузки. В общем, так называемая "универсальная ссылка" выигрывает, если const T& не является точным совпадением, и выигрывает const T&.

struct A {};

int
main()
{
    f(std::declval<A>());  // calls f<A>(A&&), #1
    f(std::declval<const A>());  // calls f<const A>(const A&&), #1
    f(std::declval<A&>());  // calls f<A&>(A&), #1
    f(std::declval<A&&>());  // calls f<A>(A&&), #1
    f(std::declval<const A&&>());  // calls f<const A>(const A&&), #1
    f(std::declval<const A&>());  // calls f<A>(const A&), #2
}

Хороший совет - перегрузка никогда, как это.