Si può solo specializzarsi in modo esplicito, fornendo tutti gli argomenti di template. Non è consentita alcuna specializzazione parziale per le funzioni membro dei modelli di classe.
template <typename T,bool B>
struct X
{
void Specialized();
};
// works
template <>
void X<int,true>::Specialized()
{
...
}
un lavoro in giro è di introdurre funzioni di sovraccarico, che hanno il vantaggio di essere ancora nella stessa classe, e in modo da avere lo stesso accesso agli stati variabili, funzioni e componenti
// "maps" a bool value to a struct type
template<bool B> struct i2t { };
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl(i2t<B>()); }
private:
void SpecializedImpl(i2t<true>) {
// ...
}
void SpecializedImpl(i2t<false>) {
// ...
}
};
Nota che, passando alle funzioni sovraccariche e inserendo i parametri del modello in un parametro di funzione, è possibile arbitrariamente "specializzare" le proprie funzioni, e potrebbe anche templatizzarle secondo necessità. Un'altra tecnica comune è quella di rinviare a un modello di classe definita separatamente
template<typename T, bool B>
struct SpecializedImpl;
template<typename T>
struct SpecializedImpl<T, true> {
static void call() {
// ...
}
};
template<typename T>
struct SpecializedImpl<T, false> {
static void call() {
// ...
}
};
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl<T, B>::call(); }
};
Trovo che di solito richiede più codice e trovo la funzione di sovraccarico più facile da gestire, mentre altri preferiscono la rinviare al modo in cui modello di classe. Alla fine è una questione di gusti. In questo caso, potresti inserire quell'altro modello all'interno di X
anche come modello annidato, in altri casi in cui ti specializzi esplicitamente invece che solo parzialmente, quindi non puoi farlo, perché puoi posizionare le specializzazioni esplicite solo nello spazio dei nomi, non in ambito di classe.
Si potrebbe anche creare un tale modello SpecializedImpl
solo per scopo della funzione di sovraccarico (allora funziona in modo simile al nostro i2t
di prima), come la seguente variante dimostra che lascia la prima variabile di parametri troppo (così si può chiamare con altri tipi - non solo con parametri di modello del di istanza corrente)
template <typename T,bool B>
struct X
{
private:
// maps a type and non-type parameter to a struct type
template<typename T, bool B>
struct SpecializedImpl { };
public:
void Specialized() { Specialized(SpecializedImpl<T, B>()); }
private:
template<typename U>
void Specialized(SpecializedImpl<U, true>) {
// ...
}
template<typename U>
void Specialized(SpecializedImpl<U, false>) {
// ...
}
};
penso che a volte, rimandando ad un altro modello è migliore (quando si tratta di casi come vettori e puntatori, il sovraccarico può difficile e solo l'inoltro a un modello di classe è stato più facile per me allora), ea volte solo un sovraccarico all'interno del modello è migliore, specialmente se proprio per argomenti della funzione di rione e se si toccano le variabili membro delle classi.
Non è del tutto chiaro cosa intendi qui. Intendi forzare il parametro template a essere il discendente di un certo tipo? Come è possibile in Java con? –
@Alcon Quando si specializza una classe template, deve fornire un'implementazione * diversa * per l'intera classe. Mi sembra che voglia condividere il codice comune tra le specializzazioni tranne alcune funzioni. – AraK
Questa domanda dovrebbe indicare "funzione membro" anziché "membro"? In modo che nessuno pensi che si tratta di membri dei dati. –