Typ automatycznego zwrotu szablonu i niejednoznaczność

20

Mam przeciążoną funkcję szablonu:

template<typename T1, typename T2>
auto overMax(T1 a, T2 b)
{
    std::cout << __FUNCSIG__ << std::endl;

    return b < a ? a : b;
}

template<typename RT, typename T1, typename T2>
RT overMax(T1 a, T2 b)
{
    std::cout << __FUNCSIG__ << std::endl;

    return b < a ? a : b;
}

Jeśli nazywam to tak:

auto a = overMax(4, 7.2); // uses first template
auto b = overMax<double>(4, 7.2); // uses second template

wszystko działa idealnie, ale

auto c = overMax<int>(4, 7.2); // error

powoduje niejednoznaczne połączenie.

Dlaczego tak jest z int , a jakie inne typy są OK?

wzmacniacz
źródło
4
Myślę, że ... .... Kompilator postrzega to następująco: z int, czy określasz typename RTczy typename T1? Ponieważ 4jest to również int, może być albo. Z double, 4nie pasuje bezpośrednio do typu double, więc preferowane jest drugie przeciążenie.
ChrisMM
Wydaje mi się to nieco podejrzane, ponieważ przeciążasz typ zwrotu, ale szablony mają różne parametry.
Borgleader

Odpowiedzi:

25

RTnie można go wydedukować, więc jeśli go nie podasz, template<typename T1, typename T2> auto overMax(T1 a, T2 b)można go wywołać tylko

Gdy (częściowo) podasz jeden argument szablonu, obie metody są wykonalne,

ale w zależności od argumentów można być lepszym kandydatem:

  • Dla auto b = overMax<double>(4, 7.2); // uses second template

    Oba overMax<double, int, double>i overMax<double, double>są opłacalne.
    Ale overMax<double, int, double>jest dokładne dopasowanie
    natomiast overMax<double, double>wymaga intdo doublekonwersji.

  • Dla auto c = overMax<int>(4, 7.2); // Ambiguous call

    Oba overMax<int, int, double>i overMax<int, double>są opłacalne.
    Ale żaden nie jest lepszym dopasowaniem ani bardziej wyspecjalizowany, więc połączenie jest niejednoznaczne.

Jarod42
źródło
dlaczego żadne z nich nie jest lepsze? Czy mam rację, że w pierwszym przypadku overMax <int> (4, 7.2); spowoduje konwersję 7.2 na int . A w drugim przypadku zwrócony wynik, który początkowo jest podwójny , zostanie przekonwertowany na int z powodu jawnego <int> ?
wzmacniacz
1
@ wzmacniacz: overMax<int>(4, 7.2)będzie w pierwszym przypadku T1=int(pod warunkiem), T2=double(wydedukowany), a w drugim przypadku RT=int(pod warunkiem), T1=int, T2=double(wydedukowany). Definicja treści obu metod nie jest używana do wybierania przeciążenia.
Jarod42
jak dla mnie, drugi przypadek jest odpowiedni, ponieważ istnieje konwersja typu zwracanego dla pierwszego i brak konwersji dla drugiego, prawda?
wzmacniacz
hmmm ... konwersja typu powrotu nie odgrywa roli ... wtedy tak, oba połączenia są równoważne z tego punktu widzenia
wzmacniacz