c++ - total - Resolución de sobrecarga y ordenamiento parcial de plantillas.
relacion de orden parcial matematicas discretas (1)
Descargo de responsabilidad: los tipos que consideramos son siempre tipos de parámetros. Los tipos / categorías de valor / etc. de los argumentos reales pasados se consideran únicamente en la resolución de sobrecarga, nunca en orden parcial.
El ordenamiento parcial considera ambas sobrecargas en dos "giros", en los que una plantilla es siempre la plantilla de parámetros , y la otra plantilla es la plantilla de argumentos . [temp.deduct.partial] / 2:
Para cada una de las plantillas involucradas está el tipo de función original y el tipo de función transformada. [..] El proceso de deducción utiliza el tipo transformado como plantilla de argumento y el tipo original de la otra plantilla como plantilla de parámetro. Este proceso se realiza dos veces para cada tipo involucrado en la comparación de ordenamiento parcial: una vez se usa la plantilla transformada-1 como la plantilla de argumentos y la plantilla-2 como la plantilla de parámetros y nuevamente se usa la plantilla-2 transformada como la plantilla de argumentos y la plantilla-1 como la plantilla de parámetros.
Debe estar familiarizado con la forma en que se generan las "plantillas" transformadas. Esto se especifica en §14.5.6.2 / 3.
Para producir la plantilla transformada, para cada tipo, no tipo o parámetro de plantilla de plantilla (incluidos los paquetes de parámetros de plantilla (14.5.3) del mismo) sintetice un tipo único, un valor o una plantilla de clase respectivamente y sustitúyalos por cada aparición de ese parámetro en el tipo de función de la plantilla.
Así que nuestras plantillas de argumento (transformadas) son
void foo( Unique1& );
void foo( Unique2 const& );
[temp.deduct.partial] / 3 & / 4:
Los tipos utilizados para determinar el orden depende del contexto en el que se realiza la ordenación parcial:
- En el contexto de una llamada de función, los tipos utilizados son aquellos tipos de parámetros de función para los cuales la llamada de función tiene argumentos. [..]
Cada tipo nominado anteriormente de la plantilla de parámetros y el tipo correspondiente de la plantilla de argumentos se utilizan como los tipos de
P
yA
Así tenemos dos turnos, y en ambos tenemos un tipo P
y un tipo A
:
Turno 1:
P1
: T const&
A1
: Unique1&
Turno 2:
P2
: T&
A2
: Unique2 const&
Pero antes de que comience la diversión, también se realizan algunas transformaciones en estos tipos - abrevié [temp.deduct.partial] / 5 & / 7:
- Si
P
oA
son referencias, entonces son reemplazadas por el tipo al que se refieren. - Se eliminan todos los calificadores cv de nivel superior.
Tenga en cuenta que los calificadores cv eliminados se "recuerdan" para más adelante. [temp.deduct.partial] / 6:
Si tanto
P
comoA
eran tipos de referencia (antes de ser reemplazados por el tipo mencionado anteriormente), determine cuál de los dos tipos (si corresponde) es más calificado como CV que el otro; de lo contrario, se considera que los tipos están igualmente calificados como CV para fines de pedido parcial. El resultado de esta determinación se utilizará a continuación.
Así nos quedamos con
Turno 1:
P1
: T
A1
: Unique1
Turno 2:
P2
: T
A2
: Unique2
Ahora realizamos la deducción, que claramente tiene éxito en ambos turnos al establecer T=Unique[1/2]
. De [temp.deduct.partial] / 8:
Si la deducción es exitosa para un tipo dado, el tipo de la plantilla de argumentos se considera al menos tan especializado como el tipo de la plantilla de parámetros.
Eso nos da a ambos que Unique1&
es al menos tan especializado como T const&
, y que Unique2 const&
es tan especializado como T&
.
Sin embargo, aquí es donde [temp.deduct.partial] / (9.2) entra en:
Si, para un tipo dado, la deducción tiene éxito en ambas direcciones (es decir, los tipos son idénticos después de las transformaciones anteriores) y tanto
P
comoA
eran tipos de referencia (antes de ser reemplazados por el tipo mencionado anteriormente):
[..]; de otra manera,
si el tipo de la plantilla de argumento es más cv calificado que el tipo de la plantilla de parámetros (como se describe anteriormente), el tipo de parámetro no se considera al menos tan especializado como el tipo de argumento.
Los calificados cv-recordados entran en juego. A2
es "más calificado como CV (como se describe anteriormente)" que P2
, por lo que P2
no se considera al menos tan especializado como A2
.
Finalmente, [temp.deduct.partial] / 10:
La plantilla de función
F
es al menos tan especializada como la plantilla de funciónG
si, para cada par de tipos utilizados para determinar el orden, el tipo deF
es al menos tan especializado como el tipo deG
F
es más especializado queG
siF
es al menos tan especializado comoG
yG
no es al menos tan especializado comoF
implica que dado que el tipo T&
no es al menos tan especializado como Unique2 const&
y ya establecimos que T const&
es al menos tan especializado como Unique1&
, el T const&
-loadload es más especializado que el T&
overload.
La regla mencionada en el párrafo 9 está actualmente sujeta al CWG # 2088 creado hace cuatro meses por R. Smith:
Se aplican los últimos desempates para las referencias lvalue-vs-rvalue y cv-qualification en 14.8.2.4 [temp.deduct.partial] párrafo 9
Si, para un tipo dado, la deducción tiene éxito en ambas direcciones (es decir, los tipos son idénticos después de las transformaciones anteriores) y tanto
P
comoA
eran tipos de referencia (antes de ser reemplazados por el tipo mencionado anteriormente):Sin embargo, esto se basa en una suposición falsa. [..] Tenemos que decidir si la regla es "la deducción tiene éxito en ambas direcciones" o "los tipos son idénticos". Este último parece más razonable.
Sin embargo, esto no alterará el resultado establecido, ya que los tipos que obtuvimos son de hecho idénticos.
Considere este simple par de plantillas de funciones.
template <typename T>
void foo(T& ) { std::cout << __PRETTY_FUNCTION__ << ''/n''; }
template <typename C>
void foo(const C& ) { std::cout << __PRETTY_FUNCTION__ << ''/n''; }
Si llamamos a foo
con un argumento no constante:
int i = 4;
foo(i);
La T&
sobrecarga se prefieren en función de [over.ics.rank] /3.2.6, ya que la referencia deducida int&
es menos cv- calificada que la referencia deducida const int&
.
Sin embargo, si llamamos a foo
con un argumento const:
const int ci = 42;
foo(ci);
Se prefiere la carga const C&
sobrecarga porque es "más especializada" en función de [over.match.best] /1.7. ¿Pero cuáles son las reglas para determinar esto? Mi entendimiento fue que sintetizas un tipo para C
(llámalo, M
) y tratas de realizar una deducción en foo(M)
, pero eso tendría éxito (con T == M
). Es solo un valor que causaría que la deducción fallara, pero ¿cómo sabe el compilador que tiene que elegir un valor en el paso de síntesis?