c++ - Resolución de sobrecarga de funciones de plantilla
templates overload-resolution (3)
la deducción de argumento de plantilla no tiene en cuenta el tipo de devolución,
Si. La deducción de argumentos de plantilla se realiza en base a argumentos de función.
Entonces, ¿por qué
max<int>
es ambiguo y nomax<double>
?
Dado
::max<int>(7, 4.)
, para la primera sobrecarga, el primer parámetro de plantilla
T1
se especifica como
int
, y
T2
se deduce como
double
del argumento de la segunda función
4.
, entonces la instanciación sería
double max(int, double)
.
Para la segunda sobrecarga, el primer parámetro de plantilla
RT
se especifica como
int
,
T1
se deduce como
int
de
7
,
T2
se deduce como
double
de
4.
, entonces la instanciación sería
int max(int, double)
.
La resolución de sobrecarga
no considera el tipo de retorno también, las dos sobrecargas son a la vez
coincidencia exacta
y luego ambiguas.
Dado
::max<double>(7, 4.)
, para la primera sobrecarga, el primer parámetro de plantilla
T1
se especifica como
double
, y
T2
se deduce como
double
de
4.
, por lo que la instanciación sería
double max(double, double)
Para la segunda sobrecarga, el primer parámetro de plantilla
RT
se especifica como
double
,
T1
se deduce como
int
de
7
,
T2
se deduce como
double
de
4.
, entonces la instanciación sería
double max(int, double)
.
Luego, la segunda sobrecarga gana en
resolución de sobrecarga
porque es una
coincidencia exacta
, la primera requiere la
conversión implícita
de
int
a
double
para el primer argumento
7
.
Considera este código:
#include <iostream>
//Number1
template<typename T1, typename T2>
auto max (T1 a, T2 b)
{
std::cout << "auto max(T1 a, T2 b)" <<std::endl;
return b < a ? a : b;
}
//Number2
template<typename RT, typename T1, typename T2>
RT max (T1 a, T2 b)
{
std::cout << "RT max(T1 a, T2 b)" << std::endl;
return b < a ? a : b;
}
int main()
{
auto a = ::max(4, 7.2); //Select Number1
auto b = ::max<double>(4, 7.4); //Select Number2
auto c = ::max<int>(7, 4.); //Compile-time error overload ambiguous
auto c = ::max<double>(7, 4.); //Select Number2
}
auto c = ::max<int>(7, 4.);
: Esta línea no se compila debido a la ambigüedad de sobrecarga con el siguiente mensaje:
maxdefault4.cpp:9:27: error: call of overloaded ''max(int, double)'' is ambiguous
auto c = ::max<int>(7, 4.);
^
maxdefault4.cpp:9:27: note: candidates are:
In file included from maxdefault4.cpp:1:0:
maxdefault4.hpp:4:6: note: auto max(T1, T2) [with T1 = int; T2 = double]
auto max (T1 a, T2 b)
^
maxdefault4.hpp:11:4: note: RT max(T1, T2) [with RT = int; T1 = int; T2 = double]
RT max (T1 a, T2 b)
^
mientras que el siguiente código:
àuto c = ::max<double>(7, 4.)
éxito, ¿por qué no tenemos el mismo mensaje de error que dice que la llamada es ambigua para
max<double>
la misma manera que
max<int>
ha fallado ?
¿Por qué para el
double
no hay problema?
He leído en el libro "Plantillas C ++, la guía completa" que la deducción de argumento de plantilla no tiene en cuenta el tipo de retorno, entonces ¿por qué
max<int>
es ambiguo y no
max<double>
?
¿El tipo de retorno de una función de plantilla realmente no se tiene en cuenta en la eliminación de argumentos?
Para cada una de sus llamadas de función, el compilador tiene 2 funciones para elegir y elige la mejor.
Los parámetros de plantilla desconocidos se deducen de los argumentos aparte de
RT
que deben especificarse explícitamente y no pueden deducirse.
auto a = ::max(4, 7.2);
Como
RT
no se especifica y no se puede deducir, la segunda sobrecarga no se puede utilizar, por lo que se ignora.
Se elige el primero y los tipos se deducen como
int
y
double
.
auto b = ::max<double>(4, 7.4);
RT
ahora se especifica para que el compilador pueda elegir usar
max<double,int,double>
o
max<double, double>
, los tipos de argumento para la versión del parámetro de 3 plantillas coinciden exactamente con los argumentos de la función, mientras que la versión del parámetro de 2 plantillas requeriría un elenco de
int
a
double
para elegir la sobrecarga de 3 parámetros.
auto c = ::max<int>(7, 4.);
RT
ahora se especifica para que el compilador pueda elegir usar
max<int,int,double>
o
max<int, double>
, los tipos de argumento de ambas funciones ahora son las mismas, por lo que el compilador no puede elegir entre ellas.
Veamos qué especifica el
double
como argumento para el compilador durante la resolución de sobrecarga.
Para la plantilla
max
"Número1", especifica que el primer argumento debe ser de tipo
double
.
Al intentar hacer la coincidencia de plantilla, el compilador deduce que el segundo argumento es de tipo
double
.
Entonces, la firma resultante es
auto max(double, double)
.
Esa es una coincidencia, aunque implica lanzar el primer argumento de
int
a
double
.
Para la plantilla
max
"Número2", especifica que el tipo de retorno es
double
.
Los tipos de argumento se deducen.
Entonces la firma resultante es
double max(int, double)
.
Esa es una coincidencia exacta, eliminando cualquier ambigüedad.
Ahora veamos cómo especificar
int
.
Ahora las dos firmas son
auto max(int, double)
y
double max(int, double)
.
Como puede ver, no hay diferencia que sea relevante para la resolución de sobrecarga, lo que resulta en la ambigüedad.
Esencialmente, al pasar el
double
, has envenenado una de las sobrecargas al forzar una conversión innecesaria;
la otra sobrecarga por lo tanto llega a dominar.
Pasar en
int
, por el contrario, no restringe aún más la capacidad de sobrecarga para ser una combinación perfecta.