Il il segreto sta nel fatto che un modello può essere specializzato per alcuni tipi. Ciò significa che può anche definire l'interfaccia completamente diversa per diversi tipi. Ad esempio è possibile scrivere:
template<typename T>
struct test {
typedef T* ptr;
};
template<> // complete specialization
struct test<int> { // for the case T is int
T* ptr;
};
Si potrebbe chiedere perché è utile e in effetti: sembra davvero inutile. Ma tieni presente che ad esempio std::vector<bool>
il tipo reference
sembra completamente diverso rispetto agli altri T
s. Certo, non cambia il tipo di reference
da un tipo a qualcosa di diverso ma ciò nonostante potrebbe accadere.
Ora cosa succede se si scrivono i propri modelli utilizzando questo modello test
. Qualcosa di simile
template<typename T>
void print(T& x) {
test<T>::ptr p = &x;
std::cout << *p << std::endl;
}
sembra essere ok per voi, perché si aspetta che test<T>::ptr
è un tipo. Ma il compilatore non lo sa e, di fatto, è addirittura consigliato dallo standard di aspettarsi il contrario, test<T>::ptr
non è un tipo. Per dire al compilatore cosa ti aspetti devi prima aggiungere un typename
. Il modello corretto appare come questa linea di fondo
template<typename T>
void print(T& x) {
typename test<T>::ptr p = &x;
std::cout << *p << std::endl;
}
: È necessario aggiungere typename
prima di ogni volta che si utilizza un tipo nidificato di un modello nei vostri modelli. (Naturalmente solo se per quel modello interno è utilizzato un parametro template del
http://stackoverflow.com/questions/1600464/ – sbi