Почему этот вызов не является шаблоном неоднозначным?

Я объявляю два шаблона, первый преобразует аргумент x из типа T в тип U а второй из типа U в тип T Если я вызываю cast с 10, компилятор не жалуется. Я думаю, что оба отвечают требованиям, которые нужно использовать, и поэтому должна быть двусмысленность, это правда? Этот код печатает 10.

#include <iostream>

template<typename T, typename U>
U cast(T x) {
    return static_cast<U>(x);
}

template<typename T, typename U>
T cast(U x) {
    return static_cast<T>(x);
}

int main() {
    std::cout << cast<int,float>(10) << '\n';
}

Ответы

Ответ 1

Когда вы используете cast<int, float>, рассматриваются оба шаблона.

template<typename T=int,typename U=float>
U cast(T x);
template<typename T=int,typename U=float>
T cast(U x);

мы затем подставляем:

template<typename T=int,typename U=float>
float cast(int x);
template<typename T=int,typename U=float>
int cast(float x);

на данный момент нет никаких типов для вывода. Поэтому мы переходим к перегрузке разрешения.

В одном случае мы можем взять int и преобразовать в float при вызове cast, а в другом мы берем int и конвертируем в int при вызове cast. Заметьте, я не смотрю на всех в литье; тело не имеет отношения к разрешению перегрузки.

Второе не-преобразование (в точке вызова) является лучшим совпадением, поэтому выбирается перегрузка.

Если вы это сделали:

std::cout << cast<int>(10) << "\n";

все становится интереснее:

template<typename T=int,typename U=?>
U cast(T x);
template<typename T=int,typename U=?>
T cast(U x);

для первого, мы не можем вывести U Для второго мы можем.

template<typename T=int,typename U=?>
U cast(int x);
template<typename T=int,typename U=int>
int cast(int x);

поэтому здесь у нас есть одна жизнеспособная перегрузка, и она используется.

Ответ 2

Создание экземпляра не является двусмысленным, поскольку аргумент функции точно соответствует первому параметру шаблона: буква 10 представляет собой int, который также явно указан для первого типа шаблона.

Вы можете сделать экземпляр неоднозначным, если тип аргумента не соответствует явно указанным типам (таким образом, требуется преобразование), например

// error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
std::cout << cast<int,float>(10u) << "\n";