Specializzazione modello di determinati membri?

È ansible specializzare determinati membri di una class template? Qualcosa di simile a:

template  struct X { void Specialized(); }; template  void X::Specialized() { ... } template  void X::Specialized() { ... } 

Ovviamente, questo codice non è valido.

Puoi solo specializzarlo in modo esplicito fornendo tutti gli argomenti del modello. Non è consentita alcuna specializzazione parziale per le funzioni membro dei modelli di class.

 template  struct X { void Specialized(); }; // works template <> void X::Specialized() { ... } 

Una soluzione è quella di introdurre funzioni sovraccariche, che hanno il vantaggio di essere ancora nella stessa class, e quindi hanno lo stesso accesso alle variabili, alle funzioni e agli elementi dei membri

 // "maps" a bool value to a struct type template struct i2t { }; template  struct X { void Specialized() { SpecializedImpl(i2t()); } private: void SpecializedImpl(i2t) { // ... } void SpecializedImpl(i2t) { // ... } }; 

Nota che passando alle funzioni sovraccariche e spingendo i parametri del modello in un parametro di funzione, puoi arbitrariamente “specializzare” le tue funzioni, e potresti anche templatizzarle secondo necessità. Un’altra tecnica comune è quella di rimandare a un modello di class definito separatamente

 template struct SpecializedImpl; template struct SpecializedImpl { static void call() { // ... } }; template struct SpecializedImpl { static void call() { // ... } }; template  struct X { void Specialized() { SpecializedImpl::call(); } }; 

Trovo che di solito richieda più codice e trovo che la funzione sovraccarico sia più facile da gestire, mentre altri preferiscono la modalità di rinvio alla class. Alla fine è una questione di gusti. In questo caso, potresti aver inserito anche quell’altro modello all’interno di X 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 class.

Puoi anche creare un modello SpecializedImpl solo per lo scopo di sovraccaricare le funzioni (funziona quindi in modo simile al nostro i2t di prima), come dimostra la seguente variante che lascia anche la prima variabile di parametro (quindi puoi chiamarla con altri tipi – non solo con i parametri del modello di istanza corrente)

 template  struct X { private: // maps a type and non-type parameter to a struct type template struct SpecializedImpl { }; public: void Specialized() { Specialized(SpecializedImpl()); } private: template void Specialized(SpecializedImpl) { // ... } template void Specialized(SpecializedImpl) { // ... } }; 

A volte penso che rimandare a un altro modello sia meglio (quando si tratta di casi come array e puntatori, l’overloading può ingannare e semplicemente l’inoltro a un modello di class è stato più facile per me allora), ea volte solo il sovraccarico all’interno del modello è migliore – specialmente se si inoltrano realmente gli argomenti delle funzioni e se si toccano le variabili membro delle classi.

Questo è quello che mi è venuto in mente, non così male 🙂

 //The generic template is by default 'flag == false' template  struct something { void doSomething() { std::cout << "something. flag == false"; } }; template  struct something : public something { void doSomething() // override original dosomething! { std::cout << "something. flag == true"; } }; int main() { something falseSomething; something trueSomething; falseSomething.doSomething(); trueSomething.doSomething(); }