C++
deducción de tipo
Buscar..
Observaciones
En noviembre de 2014, el Comité de Normalización de C ++ adoptó la propuesta N3922, que elimina la regla de deducción de tipo especial para los inicializadores automáticos y con refuerzo mediante la sintaxis de inicialización directa. Esto no es parte del estándar C ++ pero ha sido implementado por algunos compiladores.
Deducción de parámetros de plantilla para constructores.
Antes de C ++ 17, la deducción de la plantilla no puede deducir el tipo de clase para usted en un constructor. Debe especificarse explícitamente. A veces, sin embargo, estos tipos pueden ser muy engorrosos o (en el caso de las lambdas) imposibles de nombrar, por lo que tenemos una proliferación de fábricas de tipos (como make_pair()
, make_tuple()
, back_inserter()
, etc.).
Esto ya no es necesario:
std::pair p(2, 4.5); // std::pair<int, double>
std::tuple t(4, 3, 2.5); // std::tuple<int, int, double>
std::copy_n(vi1.begin(), 3,
std::back_insert_iterator(vi2)); // constructs a back_insert_iterator<std::vector<int>>
std::lock_guard lk(mtx); // std::lock_guard<decltype(mtx)>
Se considera que los constructores deducen los parámetros de la plantilla de clase, pero en algunos casos esto no es suficiente y podemos proporcionar guías de deducción explícitas:
template <class Iter>
vector(Iter, Iter) -> vector<typename iterator_traits<Iter>::value_type>
int array[] = {1, 2, 3};
std::vector v(std::begin(array), std::end(array)); // deduces std::vector<int>
Tipo de plantilla Deducción
Sintaxis genérica de plantillas
template<typename T>
void f(ParamType param);
f(expr);
Caso 1: ParamType
es una referencia o un puntero, pero no una referencia universal o directa. En este caso, la deducción de tipos funciona de esta manera. El compilador ignora la parte de referencia si existe en expr
. El compilador entonces Patronistas los partidos expr
tipo 's contra ParamType
a determing T
.
template<typename T>
void f(T& param); //param is a reference
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
f(x); // T is int, param's type is int&
f(cx); // T is const int, param's type is const int&
f(rx); // T is const int, param's type is const int&
Caso 2: ParamType
es una referencia universal o una referencia directa. En este caso, la deducción de tipo es la misma que en el caso 1 si expr
es un valor nominal. Si expr
es un valor límico, tanto T
como ParamType
se deducen como referencias de valor l.
template<typename T>
void f(T&& param); // param is a universal reference
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
f(x); // x is lvalue, so T is int&, param's type is also int&
f(cx); // cx is lvalue, so T is const int&, param's type is also const int&
f(rx); // rx is lvalue, so T is const int&, param's type is also const int&
f(27); // 27 is rvalue, so T is int, param's type is therefore int&&
Caso 3: ParamType
es un puntero ni una referencia. Si expr
es una referencia, la parte de referencia se ignora. Si expr
es const, se ignora también. Si es volátil, eso también se ignora al deducir el tipo de T.
template<typename T>
void f(T param); // param is now passed by value
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
f(x); // T's and param's types are both int
f(cx); // T's and param's types are again both int
f(rx); // T's and param's types are still both int
Deducción de tipo automático
La deducción de tipo usando la palabra clave auto
funciona casi igual que la Deducción de tipo de plantilla. Abajo hay algunos ejemplos:
auto x = 27; // (x is neither a pointer nor a reference), x's type is int
const auto cx = x; // (cx is neither a pointer nor a reference), cs's type is const int
const auto& rx = x; // (rx is a non-universal reference), rx's type is a reference to a const int
auto&& uref1 = x; // x is int and lvalue, so uref1's type is int&
auto&& uref2 = cx; // cx is const int and lvalue, so uref2's type is const int &
auto&& uref3 = 27; // 27 is an int and rvalue, so uref3's type is int&&
Las diferencias se detallan a continuación:
auto x1 = 27; // type is int, value is 27
auto x2(27); // type is int, value is 27
auto x3 = { 27 }; // type is std::initializer_list<int>, value is { 27 }
auto x4{ 27 }; // type is std::initializer_list<int>, value is { 27 }
// in some compilers type may be deduced as an int with a
// value of 27. See remarks for more information.
auto x5 = { 1, 2.0 } // error! can't deduce T for std::initializer_list<t>
Como puede ver si usa inicializadores con refuerzos, se fuerza automáticamente a crear una variable de tipo std::initializer_list<T>
. Si no puede deducir el valor de T
, el código es rechazado.
Cuando se utiliza auto
como el tipo de retorno de una función, especifica que la función tiene un tipo de retorno final .
auto f() -> int {
return 42;
}
C ++ 14 permite, además de los usos de auto permitido en C ++ 11, lo siguiente:
Cuando se usa como el tipo de retorno de una función sin un tipo de retorno final, especifica que el tipo de retorno de la función debe deducirse de las declaraciones de retorno en el cuerpo de la función, si corresponde.
// f returns int: auto f() { return 42; } // g returns void: auto g() { std::cout << "hello, world!\n"; }
Cuando se usa en el tipo de parámetro de un lambda, define el lambda como un lambda genérico .
auto triple = [](auto x) { return 3*x; }; const auto x = triple(42); // x is a const int with value 126
La forma especial decltype(auto)
deduce un tipo utilizando las reglas de deducción de decltype
de decltype
lugar de las de auto
.
int* p = new int(42);
auto x = *p; // x has type int
decltype(auto) y = *p; // y is a reference to *p
En C ++ 03 y anteriores, la palabra clave auto
tenía un significado completamente diferente como un especificador de clase de almacenamiento que se heredó de C.