2010-03-12 24 views
12

Supponiamo che abbiamo una funzione template "pippo":Un modello di specializzazione per più classi

template<class T> 
void foo(T arg) 
{ ... } 

posso fare specializzazione per un certo tipo particolare, ad esempio

template<> 
void foo(int arg) 
{ ... } 

Se voluto usare la stessa specializzazione per tutti i tipi built numerici (int, float, double ecc) vorrei scrivere quelle linee molte volte. So che il corpo può essere gettato in un'altra funzione e basta chiamare questo nel corpo di ogni specializzazione, tuttavia sarebbe meglio se potessi evitare di scrivere questo "vuoto foo (..." per ogni tipo. alcuna possibilità di dire al compilatore che voglio usare questa specializzazione per tutto questo tipo?

+3

Qual è il tuo obiettivo finale? –

+0

Questa non è una risposta diretta, ma riguarda la specializzazione rispetto al sovraccarico e potrebbe interessarti: http://www.gotw.ca/publications/mill17.htm – sellibitze

risposta

19

È possibile utilizzare std::numeric_limits per verificare se un tipo è un tipo numerico (is_specialized è vero per tutti i tipi fondamentali float e interi)

// small utility 
template<bool> struct bool2type { }; 

// numeric 
template<typename T> 
void fooImpl(T arg, bool2type<true>) { 

} 

// not numeric 
template<typename T> 
void fooImpl(T arg, bool2type<false>) { 

} 

template<class T> 
void foo(T arg) 
{ fooImpl(arg, bool2type<std::numeric_limits<T>::is_specialized>()); } 
+0

Un'idea pulita! Ma perché non fare in modo che 'fooImpl' dipenda da un tipo e da un argomento booleano? – Vlad

+1

@Vlad perché vogliamo la ramificazione del tempo di compilazione. Se passiamo un argomento di funzione 'bool', avremo il codice eseguito nella stessa funzione e useremo' if' per diramarlo. Questo sfortunatamente sfiorerà i due rami e molto probabilmente mancherà l'obiettivo. –

+0

@Johannes: intendevo due argomenti del template, solo per risparmiare la definizione di 'bool2type'. – Vlad

0

forse si può definire una funzione template di default che funziona su tutti i tipi nativi, e delegare la specializzazione di tipo personalizzato per l'utente

3

È possibile utilizzare un approccio con il preprocessore.

foo.inc:

template<> 
void foo(TYPE arg) 
{ /* do something for int, double, etc. */ } 

foo.h:

template<class T> 
void foo(T arg) 
{ /*do something */ } 

#define TYPE int 
#include "foo.inc" 
#undef TYPE 

#define TYPE double 
#include "foo.inc" 
#undef TYPE 

ecc

3

con boost:

#include <boost/type_traits/is_scalar.hpp> 
#include <iostream> 
#include <string> 

namespace detail 
{ 
    typedef const boost::true_type& true_tag; 
    typedef const boost::false_type& false_tag; 

    template <typename T> 
    void foo(const T& pX, true_tag) 
    { 
     std::cout << "special: " << pX << std::endl; 
    } 

    template <typename T> 
    void foo(const T& pX, false_tag) 
    { 
     std::cout << "generic: " << pX << std::endl; 
    } 
} 

template <typename T> 
void foo(const T& pX) 
{ 
    detail::foo(pX, boost::is_scalar<T>()); 
} 

int main() 
{ 
    std::string s = ":D"; 
    foo(s); 
    foo(5); 
} 

Si può per lo più facilmente farlo senza spinta :

#include <iostream> 
#include <string> 

// boolean stuff 
template <bool B> 
struct bool_type {}; 

typedef bool_type<true> true_type; 
typedef bool_type<false> false_type; 

// trait stuff 
template <typename T> 
struct is_scalar : false_type 
{ 
    static const bool value = false; 
}; 

#define IS_SCALAR(x) template <> \ 
      struct is_scalar<x> : true_type \ 
      { \ 
       static const bool value = true; \ 
      }; 

IS_SCALAR(int) 
IS_SCALAR(unsigned) 
IS_SCALAR(float) 
IS_SCALAR(double) 
// and so on 

namespace detail 
{ 
    typedef const true_type& true_tag; 
    typedef const false_type& false_tag; 

    template <typename T> 
    void foo(const T& pX, true_tag) 
    { 
     std::cout << "special: " << pX << std::endl; 
    } 

    template <typename T> 
    void foo(const T& pX, false_tag) 
    { 
     std::cout << "generic: " << pX << std::endl; 
    } 
} 

template <typename T> 
void foo(const T& pX) 
{ 
    detail::foo(pX, is_scalar<T>()); 
} 

int main() 
{ 
    std::string s = ":D"; 
    foo(s); 
    foo(5); 
} 
0

È possibile scrivere un piccolo script (ad es. Perl) per generare il file di origine. Crea una matrice contenente tutti i tipi che vuoi specializzare e falla scrivere l'intestazione della funzione per ognuno. Puoi persino incorporare l'esecuzione dello script nel tuo makefile per rieseguire automaticamente l'esecuzione se modifichi qualcosa.

Nota: ciò presuppone che l'implementazione di foo possa essere resa banale e simile per ciascun tipo, ad esempio semplicemente richiamando la funzione di implementazione reale. Ma evita un mucchio di template/preprocessore mumbo-jumbo che potrebbe far graffiare la testa un futuro manutentore.

Problemi correlati