Nell'era illuminata del 2016, con due nuovi standard sotto la cintura da quando è stata posta questa domanda e uno nuovo dietro l'angolo, la cosa cruciale da sapere è che i compilatori che supportano lo standard C ++ 17 compileranno il tuo codice così com'è .
Deduzione degli argomenti del modello per i modelli di classe in C ++ 17
Qui (per gentile concessione di una modifica di Olzhas Zhumabek della risposta accettata) è il documento che dettaglia le modifiche rilevanti allo standard.
Affrontare le preoccupazioni da altre risposte
L'attuale risposta più votata
Questa risposta sottolinea che "copia costruttore e operator=
" non conoscerebbero le corrette specializzazioni del modello.
Questo non ha senso, perché il costruttore di copia standard operator=
esiste solo per un tipo di modello noto :
template <typename T>
class MyClass {
MyClass(const MyClass&) =default;
... etc...
};
// usage example modified from the answer
MyClass m(string("blah blah blah"));
MyClass *pm; // WHAT IS THIS?
*pm = m;
Qui, come ho notato nei commenti, non c'è motivo per MyClass *pm
essere una dichiarazione legale con o senza la nuova forma di inferenza: MyClass
non è un tipo (è un modello), quindi non ha senso dichiarare un puntatore di tipo MyClass
. Ecco un modo possibile per correggere l'esempio:
MyClass m(string("blah blah blah"));
decltype(m) *pm; // uses type inference!
*pm = m;
Qui pm
è già del tipo corretto, quindi l'inferenza è banale. Inoltre, è impossibile mescolare accidentalmente i tipi quando si chiama il costruttore di copie:
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
Qui, pm
sarà un puntatore a una copia di m
. Qui, MyClass
viene costruito da copia, m
che è di tipo MyClass<string>
(e non di tipo inesistente MyClass
). Quindi, nel punto in cui pm
viene dedotto il tipo di, ci sono informazioni sufficienti per sapere che il tipo di modello di m
, e quindi il tipo di modello di pm
, è string
.
Inoltre, quanto segue solleverà sempre un errore di compilazione :
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
Questo perché la dichiarazione del costruttore di copia non è basata su modelli:
MyClass(const MyClass&);
Qui, il tipo di modello dell'argomento del costruttore di copia corrisponde al tipo di modello della classe nel suo complesso; cioè, quando MyClass<string>
viene istanziato, MyClass<string>::MyClass(const MyClass<string>&);
viene istanziato con esso, e quando MyClass<int>
viene istanziato, MyClass<int>::MyClass(const MyClass<int>&);
viene istanziato. A meno che non sia esplicitamente specificato o venga dichiarato un costruttore basato su modelli, non c'è motivo per il compilatore di istanziare MyClass<int>::MyClass(const MyClass<string>&);
, il che sarebbe ovviamente inappropriato.
La risposta di Cătălin Pitiș
Pitiș fa un esempio deducendo Variable<int>
e Variable<double>
, quindi afferma:
Ho lo stesso nome di tipo (variabile) nel codice per due diversi tipi (variabile e variabile). Dal mio punto di vista soggettivo, influisce molto sulla leggibilità del codice.
Come notato nell'esempio precedente, di per Variable
sé non è un nome di tipo, anche se la nuova funzionalità lo fa sembrare sintatticamente simile.
Pitiș chiede quindi cosa accadrebbe se non fosse fornito alcun costruttore che consentirebbe l'inferenza appropriata. La risposta è che non è consentita alcuna inferenza, perché l'inferenza viene attivata dalla chiamata al costruttore . Senza una chiamata al costruttore, non c'è inferenza .
Questo è simile a chiedere quale versione di foo
viene dedotta qui:
template <typename T> foo();
foo();
La risposta è che questo codice è illegale, per il motivo dichiarato.
La risposta di MSalter
Questa è, per quanto ne so, l'unica risposta per sollevare una legittima preoccupazione sulla funzionalità proposta.
L'esempio è:
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
La domanda chiave è: il compilatore seleziona qui il costruttore dedotto dal tipo o il costruttore di copia ?
Provando il codice, possiamo vedere che il costruttore di copia è selezionato. Per espandere l'esempio :
Variable var(num); // infering ctor
Variable var2(var); // copy ctor
Variable var3(move(var)); // move ctor
// Variable var4(Variable(num)); // compiler error
Non sono sicuro di come la proposta e la nuova versione dello standard lo specifichino; sembra essere determinato da "guide alla deduzione", che sono un nuovo pezzo di standardese che ancora non capisco.
Inoltre, non sono sicuro del motivo per cui la var4
detrazione è illegale; l'errore del compilatore da g ++ sembra indicare che l'istruzione viene analizzata come una dichiarazione di funzione.