Автоматический возврат типа шаблона и неоднозначность

20

У меня перегружена функция шаблона:

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;
}

Если я назову это так:

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

все работает отлично, но

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

вызывает неоднозначный вызов.

Почему это так с int , и хорошо, какие другие типы?

усилитель
источник
4
Я думаю… .... То, как это видит компилятор: с int, вы указываете typename RTили typename T1? Так как 4это тоже intможет быть. С double, 4не соответствует напрямую типу double, поэтому вторая перегрузка предпочтительнее.
ChrisMM
Мне это кажется немного странным, потому что вы как бы перегружаете возвращаемый тип, но с шаблонами, которые имеют разное количество параметров.
Borgleader

Ответы:

25

RTне подлежит вычету, поэтому, если его не предоставить, template<typename T1, typename T2> auto overMax(T1 a, T2 b)можно вызвать только .

Когда вы (частично) предоставляете один аргумент шаблона, оба метода являются жизнеспособными,

но в зависимости от аргумента, один может быть лучшим кандидатом:

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

    Оба overMax<double, int, double>и overMax<double, double>жизнеспособны.
    Но overMax<double, int, double>это точное совпадение ,
    тогда как overMax<double, double>требуется intдля doubleпреобразования.

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

    Оба overMax<int, int, double>и overMax<int, double>жизнеспособны.
    Но ни один из них не является лучшим или более специализированным, поэтому вызов неоднозначен.

Jarod42
источник
почему ни один из них не намного лучше? Прав ли я, что в первом случае overMax <int> (4, 7.2); вызовет преобразование 7,2 в Int . А во втором случае возвращаемый результат, который изначально является двойным , будет преобразован в int из-за явного <int> ?
усилитель
1
@amplifier: overMax<int>(4, 7.2)будет в первом случае T1=int(при условии), T2=double(вывод) и во втором случае RT=int(при условии), T1=int, T2=double(вывод). Содержимое определения обоих методов не используется для выбора перегрузки.
Jarod42
для меня подходит второй случай, так как для первого есть преобразование типа возврата, а для второго вообще нет преобразования, не так ли?
усилитель
хммм ... преобразование типа возврата не играет роли ... тогда да, оба вызова эквивалентны с этой точки зрения
усилитель