Buenas tardes, querido lector!
Este artículo es el primero de una serie de artículos abstractos que escribiré mientras leo el libro de Scott Meyers, Effective and Modern c ++. Cada uno de estos artículos tendrá un directorio separado en un proyecto especialmente instituido en github.com con ejemplos del uso de las características y técnicas descritas.
Inferencia de tipo de plantilla
El diseño exitoso es cuando el consumidor no sabe cómo funciona el dispositivo, pero todo le conviene.
La conclusión del tipo de plantilla es cuando hay una función de plantilla, por ejemplo, y se llama sin plantilla ni corchetes angulares. Al mismo tiempo, el compilador adivina qué tipo necesitará usar en un objeto particular de la función.
Meyers divide el tipo - "T" , que se muestra y el tipo - "ParamType" , que prescribe el programador en la definición del parámetro.
1. Vista de parámetros: enlace o puntero
Para comprender rápidamente la regla de derivación, la reflejaré en forma de plantilla:
tipo de entrada -> tipo, parámetro -> tipo de salida [, tipo final del parámetro ]
Ejemplo con un enlace:
template<typename T> // T void func(T& param) // - T& int x = 0; // int func(x);
Cuando se deriva el tipo T , la referencialidad (*, &) se descarta porque ya está indicada al definir la función, como si significa "pasa algo allí, asumiremos que esto no es un enlace, porque la referencialidad ya está agregada en el lugar de consumo - en nuestra función f "
Por el mismo principio, la constancia se descarta si se especifica en el parámetro de función. En enlaces, punteros, constancia, por así decirlo, se impone una máscara exclusiva.
Esquema de Retiro
// int —> (T & param) —> int; const int —> (T & param) —> const int; const int & —> (T & param) —> const int // int —> (const T & param) —> int; const int —> (const T & param) —> int; const int & —> (const T & param) —> int; // int * —> (T * param) —> int; const int —> (T * param) —> const int; const int * —> (T * param) —> const int; // int * —> (const T * param) —> int; const int —> (const T * param) —> int; const int * —> (const T * param) —> int;
2. Tipo de argumento - referencia universal
Scott menciona que los enlaces universales se considerarán más adelante, por lo que las reglas para los parámetros que divide aquí en rvalue y lvalue solo deben recordarse con poco pensamiento.
template<typename T> void func(const T&& param)
Reglas de inferencia para lvalue
Este, afirma Scott, es el único caso en el que T se emite como referencia.
En los siguientes ejemplos, el tipo de parámetro en la descripción de la función es una referencia de valor universal . Se puede ver que T se muestra como un enlace o un enlace constante, dependiendo
desde el argumento de entrada, el tipo del parámetro param también es una referencia en este caso.
lvalue int —> (T &¶m) —> int &, param - int& lvalue const int —> (T &¶m) —> const int &, param - const int& lvalue const int & —> (T &¶m) —> const int &, param - const int&
El tipo del parámetro en sí también se reemplaza. Creo que esto se debe al hecho de que el lenguaje no puede considerar una variable lvalue asignada en algún lugar por encima de la que se puede mover más. Lo resolveremos más adelante cuando lleguemos a los enlaces universales.
Para verificar que T es realmente una referencia de tipo, escribí T myVar en el cuerpo de la función de plantilla, que esta T mostraba y esperaba recibir un mensaje - "declarado como referencia pero no inicializado" - el enlace :)
Reglas de inferencia para rvalue
Se aplican las reglas "normales" del párrafo 1.
rvalue int —> (T &¶m) —> int, param - int&&
Ya es evidente que las referencias universales están "incluidas" solo para objetos temporales de rvalue, en otros casos, cuando el argumento no es una referencia universal, rvalue, lvalue no se distingue
3. Pase por valor (como es)
Al pasar por valor, la constancia y referencialidad del argumento original se descarta como innecesaria porque son objetos independientes completamente nuevos, ¿por qué necesitan calificadores de aquello con lo que no están conectados?
int —> (T param) —> int const int —> (T param) —> int const int & —> (T param) —> int
Supongo que otras combinaciones locas e ilógicas causarán errores de compilación, casi siempre resulta que el trabajo del compilador es comprensible, solo necesita escuchar estas explicaciones una vez.