vectores resueltos programacion libreria fuente example ejercicios ejemplos colas codigo arreglos c++ function templates overload-resolution

resueltos - vector c++ example



La plantilla de C++ tiene prioridad (3)

#include <iostream> template <class U, class T> void foo(U&, T&) { std::cout << "first"; } template <class T> void foo(int&, const T&) { std::cout << "second"; } int main() { int a; double g = 2.; foo(a, g); // prints "first" return 0; }

Para llamar a la segunda sobrecarga de foo , el compilador necesita realizar solo una deducción de tipo de plantilla, pero para la primera sobrecarga, necesita realizar dos. ¿Puedes explicar por qué se llama la primera sobrecarga?


La resolución de sobrecarga se realiza en varios pasos.

Primero, a través de la búsqueda de nombres, seleccionamos la lista de candidatos viables. En este caso, eso es:

template <class U, class T> void foo(U&, T&); // with U = int, T = double template <class T> void foo(int&, const T&) // with T = double

A continuación, determinamos la secuencia de conversión necesaria para cada argumento para cada candidato viable. Esto es [over.ics.rank]:

La secuencia de conversión estándar S1 es una secuencia de conversión mejor que la secuencia de conversión estándar S2 si [...]

  • S1 es una subsecuencia adecuada de S2 (que compara las secuencias de conversión en la forma canónica definida en 13.3.3.1.1, excluyendo cualquier transformación Lvalue, la secuencia de conversión de identidad se considera una subsecuencia de cualquier secuencia de conversión no identidad) o, si eso no,
  • el rango de S1 es mejor que el rango de S2, o S1 y S2 tienen el mismo rango y se distinguen por las reglas en el siguiente párrafo, o, si no es así,

Para la primera llamada, la secuencia de conversión es (Identidad, Identidad). Para la segunda llamada, la secuencia de conversión es (Identidad, Identidad). Entonces somos iguales allí. Ninguno de esos puntos distinguen las dos llamadas. Así que seguimos adelante.

  • S1 y S2 son enlaces de referencia (8.5.3) y ninguno se refiere a un parámetro de objeto implícito de una función miembro no estática declarada sin un calificador ref, y S1 vincula una referencia rvalue a un valor r y S2 vincula una referencia lvalor.

Irrelevante.

  • S1 y S2 son enlaces de referencia (8.5.3) y S1 vincula una referencia lvalue a un valor l de la función y S2 vincula una referencia rvalue a un valor l de la función.

Nop.

  • S1 y S2 difieren solo en su conversión de calificación y producen tipos similares T1 y T2 (4.4), respectivamente, y la firma de calificación cv de tipo T1 es un subconjunto propio de la firma de calificación cv de tipo T2.

La conversión de calificación es una cosa de puntero, no.

  • S1 y S2 son enlaces de referencia (8.5.3), y los tipos a los que se refieren las referencias son del mismo tipo excepto para cv-qualifiers de nivel superior, y el tipo al que la referencia inicializada por S2 se refiere es más cv-qualified que el tipo al que se refiere la referencia inicializada por S1.

En este caso, la primera sobrecarga toma su segundo argumento como double& mientras que la segunda sobrecarga toma una const double& . El primero está menos calificado que el segundo, así que nos detenemos aquí, prefiriendo a foo(U&,T&) .

Solo después de los pasos para determinar qué secuencia de conversión es mejor, llegamos al paso en que se prefiere la plantilla más especializada. El orden completo de las reglas en [over.match.best] es:

Dadas estas definiciones, una función viable F1 se define como una función mejor que otra función viable F2 si para todos los argumentos i, ICSi (F1) no es una secuencia de conversión peor que ICSi (F2), y luego

  • para algún argumento j, ICSj (F1) es una mejor secuencia de conversión que ICSj (F2), o, si no es así,

Eso es lo que acabamos de pasar.

  • el contexto es una inicialización por conversión definida por el usuario [...]
  • el contexto es una función de inicialización por conversión para enlace directo de referencia [...]
  • F1 no es una especialización de plantilla de función y F2 es una especialización de plantilla de función, o, si no es eso,
  • F1 y F2 son especializaciones de plantilla de función, y la plantilla de función para F1 es más especializada que la plantilla para F2 de acuerdo con las reglas de ordenamiento parcial descritas en 14.5.6.2.

Es por eso que elegimos foo(U&, T&) . Sin embargo, si elimina la const , ambas secuencias de conversión son idénticas en todos los pasos, por lo que en ese punto, la plantilla más especializada ( foo(int&, T&) ) ganaría.

Tenga en cuenta que más especializado es el último mecanismo para determinar el mejor candidato. Es el último de los desempates.

También tenga en cuenta que el número de deducciones de plantilla es irrelevante. Puede importar al seleccionar entre sobrecarga que es una plantilla y una sobrecarga que no es una plantilla, pero no importa al seleccionar entre una sobrecarga que tiene x parámetros de plantilla y una sobrecarga que tiene parámetros de plantilla y> x .


Observar:

  • La primera sobrecarga toma un valor l no const como segundo argumento
  • La segunda sobrecarga toma una const lvalue como segundo argumento

Como está pasando g como valor g no const, el compilador elige la primera sobrecarga.


Usted declara en la segunda función que el segundo argumento es const . El siguiente ejemplo de su corrección aplicada llama al segundo:

#include <iostream> template <class U, class T> void foo(U&, T&) { std::cout << "first"; } template <class T> void foo(int&, T&) { std::cout << "second"; } int main() { int a; double g = 2.; foo(a, g); return 0; }

Por otro lado, cuando declaras explícitamente un segundo argumento, haz const en main() , la aplicación llama a la segunda función en el ejemplo anterior como se esperaba:

#include <iostream> template <class U, class T> void foo(U&, T&) { std::cout << "first"; } template <class T> void foo(int&, const T&) { std::cout << "second"; } int main() { int a; const double g = 2.; foo(a, g); return 0; }