2013-03-04 10 views
21
// template specialization 
#include <iostream> 
using namespace std; 

// class template: 
template <class T> 
class mycontainer { 
    T element; 
    public: 
    mycontainer (T arg) {element=arg;} 
    T increase() { 

    //if(T.type==int)//how to do this or something similar? 
    //do this if an int 
    return ++element; 

    //if(T.type==char) 
    //if ((element>='a')&&(element<='z')) 
     //element+='A'-'a'; 
     //return element; 

    } 
}; 

So come scrivere una specializzazione di modello e faccio una def di classe intera separata solo per il tipo di carattere.come fare un altro tipo di tipo in secondo luogo nel modello C++?

E se volessi gestire tutto in un solo blocco di codice?

Come posso verificare se T è un int o un carattere?

risposta

19

Si potrebbe utilizzare typeid:

if (typeid(T) == typeid(int)) 

Oppure si potrebbe usare il std::is_same tipo di tratto:

if (std::is_same<T, int>::value) 
+0

Se solo ci fosse un 'static_if' ... forse questo risolverà la stessa cosa – David

+2

Ci sono state molte proposte per un' static_if' ma tutti hanno avuto i problemi. SG8 ha scritto [un'analisi delle proposte] (https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg&authuser=0) recentemente. –

+4

@JosephMansfield Il link che hai fornito non ha anteprima. – kevin

10

Ciò che si vuole è probabilmente qualcosa di simile a un compile-time if. Sfortunatamente, C++ 11 non ha supporto nativo per questo costrutto linguistico.

Tuttavia, se si desidera solo per controllare se due tipi sono identici, il std::is_same<> tipo di caratteristica dovrebbe aiutare:

#include <type_traits> // <== INCLUDE THIS STANDARD HEADER 

// class template: 
template <class T> 
class mycontainer 
{ 
    T element; 
public: 
    mycontainer (T arg) {element=arg;} 
    T increase() 
    { 
     if (std::is_same<T, int>::value) // <== THIS IS HOW YOU WOULD USE IT 
      return ++element; 

     if (std::is_same<T, char>::value) // <== THIS IS HOW YOU WOULD USE IT 
     { 
      if ((element>='a') && (element<='z')) 
       element+='A'-'a'; 
     } 

     return element; 
    } 
}; 

Tuttavia, tenere presente che la condizione viene valutata a run-time, anche se il valore di is_same<T, int>::value è noto in fase di compilazione. Ciò significa che il true e il filiale della riga if devono compilare!

Per esempio, il seguente non sarebbe legale:

if (std::is_same<T, int>::value) 
{ 
    cout << element; 
} 
else if (std::is_same<T, my_class>::value) 
{ 
    element->print(); // Would not compile when T is int! 
} 

Inoltre, come Xeo giustamente sottolineato nei commenti, il compilatore probabilmente emettere avvisi perché la sua condizione sarà sempre valutata come true oa false, quindi uno dei due rami conterrà un codice irraggiungibile.

+0

C++ ha 'if' in fase di compilazione: si chiama risoluzione di sovraccarico della funzione. –

+0

E questo significa anche che si ricevono avvisi per i rami che non sono utilizzati. La migliore forma di questo sarebbe il tag-dispatching, e ho pensato a questo per la mia risposta, ma il semplice sovraccarico fa anche il lavoro. – Xeo

+0

@JamesKanze: Non è niente come un vero costrutto 'static if'. –

6

Che ne dici di un semplice sovraccarico?

// in the private section 
static int& do_increase(int& i){ return ++i; } 
static char& do_increase(char& c){ 
    if(c >= 'a' && c <= 'z') 
    c += 'A' - 'a'; 
    return c; 
} 
template<class U> 
static U& do_increase(U& arg){ 
    // some default implementation? 
    return arg; 
} 

(Si noti che la norma non garantisce ordine alfabetico per i valori numerici di un char.)

Poi semplicemente chiamare che increase come return do_increase(element);.

3

La solita soluzione qui è di inoltrare a una funzione sovraccaricata con un argomento aggiuntivo. Qualcosa di simile:

template <typename T> 
class MyContainer 
{ 
    T increase(int const*) { /* special treatment for int */ } 
    T increase(...)  { /* default treatment   */ } 
public: 
    T increase() 
    { 
     return increase((T const*)0); 
    } 
}; 

Con un po 'di fantasia, si può trovare con tutti i tipi di distinzioni. Se si effettua le funzioni di destinazione con l'extra argomenti modelli, è possibile anche sfruttare off SFINAE: disegno l'argomento fittizio in modo che tipo di modello di sostituzione non riesce e la funzione non sarà considerata nel set di sovraccarico. E poiché tutte le funzioni sono in linea, è probabile che ci sia senza costi aggiuntivi, a condizione che si ottimizzi.

+0

La chiamata interna "aumento" non ha bisogno dell'argomento modello (in realtà, sarebbe un errore). – Xeo

+0

@Xeo corretto. Inizialmente ho fatto qualcosa di più generico, il che ha richiesto che le due funzioni di destinazione fossero dei template (affinché SFINAE entrasse in gioco). Lo aggiusterò qui. –

0

Questo è il modo di rispondere di Andy Prowls ma è tutto fatto in fase di compilazione utilizzando una classe di helper minima con specializzazione.

In questo caso si dispone di un helper che esegue effettivamente la specializzazione ma si può anche fare in modo che la classe helper prenda un bool e quindi utilizzi qualcosa come std::is_same<T, int>::value per passare quel valore come parametro del modello.

template <typename T> 
struct myContainerHelper; 
{ 
    // General Case 
    static inline T increase(T element) 
    { 
     return ++element; 
    } 
}; 

template <> 
struct myContainerHelper<char> 
{ 
    // Specific case 
    static inline char increase(char element) 
    { 
     if ((element>='a')&&(element<='z')) element+='A'-'a'; 
     return element; 
    } 
}; 

template <class T> 
class mycontainer 
{ 
    T element; 
public: 
    mycontainer (T arg) {element=arg;} 
    T increase() 
    { 
     return myContainerHelper<T>::increase(element); 
    } 
}; 

Ciò consente di specializzare solo la funzione singola anziché l'intera classe. Sto usando una classe template con statica perché sono abituato alle limitazioni VS2012 con specializzazione parziale per i modelli di funzione.

5

È possibile utilizzare esplicito modello di specializzazione

#include <iostream> 
using namespace std; 

// class template: 
template <class T> 
class mycontainer { 
    T element; 
    public: 
    mycontainer (T arg) {element=arg;} 
    T increase(); 
}; 


template<> 
int mycontainer<int>::increase(){ 
    return ++element; 
} 

template<> 
char mycontainer<char>::increase(){ 
    if ((element>='a')&&(element<='z')) 
     element+='A'-'a'; 
    return element; 
} 

int main(){ 
     mycontainer<int> A(10); 
     mycontainer<char> B('x'); 

     cout << A.increase() <<endl; 
     cout << B.increase() <<endl; 
     return 0; 
} 
+0

Mi piace questa soluzione – Dmitri

Problemi correlati