2009-10-01 18 views
23

È possibile specializzare determinati membri di una classe modello? Qualcosa di simile:Specializzazione modello di determinati membri?

template <typename T,bool B> 
struct X 
{ 
    void Specialized(); 
}; 

template <typename T> 
void X<T,true>::Specialized() 
{ 
    ... 
} 

template <typename T> 
void X<T,false>::Specialized() 
{ 
    ... 
} 

Ofcourse, questo codice non è valido.

+0

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 ? –

+1

@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

+0

Questa domanda dovrebbe indicare "funzione membro" anziché "membro"? In modo che nessuno pensi che si tratta di membri dei dati. –

risposta

3

Questo è quello che mi è venuta, non è così male :)

//The generic template is by default 'flag == false' 
template <class Type, bool flag> 
struct something 
{ 
    void doSomething() 
    { 
     std::cout << "something. flag == false"; 
    } 
}; 

template <class Type> 
struct something<Type, true> : public something<Type, false> 
{ 
    void doSomething() // override original dosomething! 
    { 
     std::cout << "something. flag == true"; 
    } 
}; 

int main() 
{ 
    something<int, false> falseSomething; 
    something<int, true> trueSomething; 

    falseSomething.doSomething(); 
    trueSomething.doSomething(); 
} 
+5

Non sei sopraffatto, ti stai solo nascondendo. – curiousguy

26

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.

+0

+1 Belle soluzioni eleganti davanti ai miei occhi. – AraK

+0

grazie, apprezzato :) –

+0

Ora che C++ 11 è fuori, questo dovrebbe usare 'std :: integral_constant' che penso. Mi correggerei, ma è una vera seccatura nella visualizzazione mobile su iPod Touch ... – Xeo

Problemi correlati