2012-01-13 19 views
11

Sto provando a far sì che la mia funzione template produca un errore in fase di compilazione se la versione base non specializzata è istanziata. Ho provato il solito schema di asserzione in fase di compilazione (dimensione array negativa) ma la compilazione ha esito negativo anche quando il modello non è istanziato. Qualche idea su come farlo fallire se e solo se la funzione template di base viene istanziata?Come imporre l'uso della specializzazione del modello?

template<class Foo> void func(Foo x) { 
    // I want the compiler to complain only if this function is instantiated. 
    // Instead, the compiler is complaining here at the declaration. 
    int Must_Use_Specialization[-1]; 
} 

template<> void func(int x) { 
    printf("Hi\n"); 
} 

risposta

1

Basta usare Boost.StaticAssert

(Edit: o static_assert se si dispone di C++ 11 sostegno che ho dimenticato.).

+1

Dovrebbe essere solo 'static_assert' (una parola chiave, non una funzione di libreria). – UncleBens

+0

corretto, grazie! – Useless

17

Non definendolo è la soluzione più semplice:

template<class Foo> void func(Foo x); 

template<> void func(int x) { 
    printf("Hi\n"); 
} 

si può anche definire in file CPP e use this che funzionerà.

E metodo Assert static:

template<class Foo> void func(Foo x) { 
    static_assert(sizeof(Foo) != sizeof(Foo), "func must be specialized for this type!"); 
} 
+2

Vorrei cambiare il messaggio in "" func deve essere specializzato per questo tipo! "' Per chiarimenti –

+0

Ho pensato ad un altro modo che funziona. Basta fare riferimento a un membro della classe inesistente è la funzione di base. – drwowe

5

Bisogna renderlo dipendente da Foo, in questo modo:

int Must_Use_Specialization[-sizeof(Foo)]; 
6

In C++ 11 è possibile utilizzare static_assert come questo:

template<typename T> struct fake_dependency: public std::false_type {}; 
template<class Foo> void func(Foo x) { 
    static_assert(fake_dependency<Foo>::value, "must use specialization"); 
} 

La struttura fake_dependency è necessaria per rendere dipendente l'asser sul parametro del modello, quindi attende con la valutazione, finché il modello non viene istanziato. È allo stesso modo possibile correggere la vostra soluzione in questo modo:

template<class> struct fake_dependency { enum {value = -1 }; }; 

template<class Foo> void func(Foo x) { 
    int Must_Use_Specialization[fake_dependency<Foo>::value]; 
} 

Vedi anche here for a live demo.

+0

Che funziona. Ho anche pensato ad altre soluzioni che funzionano: referenziare un membro inesistente, quindi la funzione di base diventa: modello void func (Foo x) { x. You_must_call_a_specialization_of_this_function; } – drwowe

+0

@ user1148117: Dato un numero infinito di classi potenziali, è difficile garantire che alcuni Foo non abbiano questo membro :) – UncleBens

+0

Un altro modo per creare una dipendenza su un argomento modello senza dover creare un tipo aggiuntivo è usare 'static_assert (sizeof (T) == 0," ... ");'. Funziona poiché lo standard specifica che ogni tipo (anche le strutture vuote) hanno una dimensione di almeno 1. Si noti che alcuni compilatori consentono tipi di lunghezza 0 sotto forma di estensione di un linguaggio (es. GCC ["Strutture senza membri"] (https : //gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Empty-Structures.html)). –

3

Non hai bisogno del modello di base se non lo utilizzerai mai! Basta fornire sovraccarichi per i tipi che si desidera utilizzare do!

void func(int x) { 
    printf("Hi 1\n"); 
} 

void func(double x) { 
    printf("Hi 2\n"); 
} 

void func(Bar x) { 
    printf("Hi 3\n"); 
} 

questo modo si ottiene un errore di compilazione per func(foo); (a meno che foo è convertibile in uno degli altri tipi).

+0

+1 per preferire i sovraccarichi alla specializzazione delle funzioni del modello! – AJG85

Problemi correlati