C++
tipo deduzione
Ricerca…
Osservazioni
A novembre 2014, il Comitato di standardizzazione del C ++ ha adottato la proposta N3922, che elimina la speciale regola di deduzione del tipo per gli inizializzatori automatici e rinforzati usando la sintassi di inizializzazione diretta. Questo non fa parte dello standard C ++ ma è stato implementato da alcuni compilatori.
Deduzione del parametro Template per costruttori
Prima di C ++ 17, la deduzione del modello non può dedurre il tipo di classe per te in un costruttore. Deve essere specificato esplicitamente. A volte, tuttavia, questi tipi possono essere molto ingombranti o (nel caso di lambda) impossibili da nominare, quindi abbiamo una proliferazione di fabbriche di tipi (come make_pair()
, make_tuple()
, back_inserter()
, ecc.).
Questo non è più necessario:
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)>
Si presume che i costruttori deducano i parametri del modello di classe, ma in alcuni casi questo non è sufficiente e possiamo fornire guide esplicative sulla deduzione:
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>
Detrazione del tipo di modello
Sintassi generica dei modelli
template<typename T>
void f(ParamType param);
f(expr);
Caso 1: ParamType
è un riferimento o un puntatore, ma non un riferimento universale o ParamType
. In questo caso, la deduzione di tipo funziona in questo modo. Il compilatore ignora la parte di riferimento se esiste in expr
. Il compilatore quindi modellisti partite expr
tipo S' contro 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
è un riferimento universale o di riferimento ParamType
. In questo caso, la deduzione di tipo è la stessa del caso 1 se l' expr
è un valore. Se expr
è un lvalue, sia T
che ParamType
sono dedotti come riferimenti lvalue.
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
è né un puntatore né un riferimento. Se expr
è un riferimento, la parte di riferimento viene ignorata. Se expr
è const che viene ignorato pure. Se è volatile, viene anche ignorato quando si deduce il tipo di 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
Deduzione del tipo automatico
Digitare la deduzione utilizzando la parola chiave auto
funziona quasi come Deduzione tipo di modello. Di seguito sono riportati alcuni esempi:
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&&
Le differenze sono descritte di seguito:
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>
Come puoi vedere se usi inizializzatori rinforzati, auto è costretto a creare una variabile di tipo std::initializer_list<T>
. Se non può dedurre il valore di T
, il codice viene rifiutato.
Quando auto
è usato come tipo di ritorno di una funzione, specifica che la funzione ha un tipo di ritorno finale .
auto f() -> int {
return 42;
}
C ++ 14 consente, oltre agli usi di auto consentiti in C ++ 11, i seguenti:
Se utilizzato come tipo di ritorno di una funzione senza un tipo di ritorno finale, specifica che il tipo di ritorno della funzione deve essere dedotto dalle istruzioni di ritorno nel corpo della funzione, se presenti.
// f returns int: auto f() { return 42; } // g returns void: auto g() { std::cout << "hello, world!\n"; }
Quando viene utilizzato nel tipo di parametro di una lambda, definisce la lambda come una lambda generica .
auto triple = [](auto x) { return 3*x; }; const auto x = triple(42); // x is a const int with value 126
La forma speciale decltype(auto)
deduce un tipo usando le regole di deduzione tipo di decltype
piuttosto che quelle di auto
.
int* p = new int(42);
auto x = *p; // x has type int
decltype(auto) y = *p; // y is a reference to *p
In C ++ 03 e precedenti, la parola chiave auto
aveva un significato completamente diverso come identificatore di una classe di memoria ereditata da C.