c++ templates overload-resolution

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 no max<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.