Tipo de devolución automática de plantilla y ambigüedad

20

Tengo una función de plantilla sobrecargada:

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

Si lo llamo así:

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

todo funciona perfecto, pero

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

provoca llamadas ambiguas.

¿Por qué es así con int y OK qué otros tipos?

amplificador
fuente
44
Creo que ... La forma en que el compilador lo ve es: con int, ¿está especificando el typename RTo el typename T1? Como 4también es un int, podría ser cualquiera. Con double, 4no coincide directamente con el tipo double, por lo que se prefiere la segunda sobrecarga.
ChrisMM
Esto me parece un poco dudoso porque estás sobrecargando el tipo de retorno pero con plantillas que tienen una cantidad diferente de parámetros.
Borgleader

Respuestas:

25

RTno es deducible, por lo que cuando no se proporciona, solo template<typename T1, typename T2> auto overMax(T1 a, T2 b)se puede llamar.

Cuando proporciona (parcialmente) un argumento de plantilla, ambos métodos son viables,

pero dependiendo del argumento, uno puede ser un mejor candidato:

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

    Ambos overMax<double, int, double>y overMax<double, double>son viables.
    Pero overMax<double, int, double>es coincidencia exacta
    mientras que overMax<double, double>se requiere intpara doublela conversión.

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

    Ambos overMax<int, int, double>y overMax<int, double>son viables.
    Pero ninguno de los dos es mejor o más especializado, por lo que la llamada es ambigua.

Jarod42
fuente
¿Por qué ninguno de ellos es mucho mejor? ¿Tengo razón en que en el primer caso overMax <int> (4, 7.2); causaría la conversión de 7.2 a int . Y en el segundo caso, el resultado devuelto, que inicialmente es doble , se convertiría a int debido a <int> explícito ?
amplificador
1
@amplificador: overMax<int>(4, 7.2)sería en el primer caso T1=int(proporcionado), T2=double(deducido) y en el segundo caso RT=int(proporcionado), T1=int, T2=double(deducido). La definición de contenido de ambos métodos no se utiliza para seleccionar la sobrecarga.
Jarod42
En cuanto a mí, el segundo caso es adecuado, ya que hay conversión de tipo de retorno para el primero y ninguna conversión para el segundo, ¿no?
amplificador
hmmm ... la conversión de tipo de retorno no juega un papel ... entonces, sí, ambas llamadas son equivalentes desde este punto de vista
amplificador