2015-05-17 3 views
5
template<typename T, typename U = void> 
struct S { /* static_assert(0, "type unsupported"); */ }; 
template<typename T> 
struct S<T, typename std::enable_if<std::is_integral<T>::value, void>::type> { 
    void foo() {} 
}; 
... 
S<int> i; 
i.foo(); 
S<double> d; 
// d.foo(); 

sarei aspettavo che il "schema generale" non sarebbe mai stato istanziato per il caso di int, ma se devo togliere il commento alla static_assert, l'istanza S<int> mancherò. Anche un solo typedef S<int> Si; non riuscirebbe a compilare. (GCC 4.9.2 Cygwin)static_assert con il modello di specializzazione parziale

Quello che mirava a realizzare non è per S<double> a fallire alla chiamata foo(), ma l'istanza del modello stesso, e che con un messaggio di errore significativo. Sono consapevole che posso fare qualcosa come typename T::nonexistent_type t; nel modello principale che impedirà il modello per la compilazione, ma che sarebbe inferiore a un messaggio static_assert. (Nota: mettere il static_assert all'interno di una definizione di funzione nel modello maestro non riesce ancora compilation per S<int>)

Perché il static_assert non riuscire anche se questo modello non viene creata un'istanza? È questo mandato (o forse "non specificato") dallo standard? C'è un modo per fallire con un static_assert nel modo in cui desidero?

+0

vedere [Perché il 'static_assert' viene sempre richiamato?] (Http://stackoverflow.com/q/27738971/3953764) –

risposta

7

L'espressione nel numero static_assert deve dipendere da un parametro modello se si desidera che sia solo tempo di istanza. Questo è garantito da Standard, l'implementazione può (ma non ha alcun obbligo) di controllare i valori static_assertion s in modelli che non dipendono da alcun parametro del modello.

Il codice è un modo indiretto strano di fare qualcosa di simile

template<typename T> struct S { 
    static_assert(std::is_integral<T>::value, "type unsupported"); 
    void foo() {} 
}; 

Questo comunica chiaramente al compilatore la dipendenza tra l'espressione e il parametro del modello, ed è molto più chiaro e più facile da leggere pure. In realtà non riuscivo a capire se volevi che la compilazione fallisse per i tipi interi o per i tipi non integrali.

+0

Ho ridotto il mio problema originale a quello più semplice per dimostrare il problema. Ho bisogno di discernere vari casi al momento della compilazione e fallire per qualsiasi altra cosa, non corrispondente alle molte specializzazioni parziali. Quindi il codice sopra. Mi sono appena reso conto che * qualsiasi * dipendenza dal tipo è sufficiente: 'static_assert :: value && 0," type unsupported ">' fa quello che voglio. (quasi - 'typedef S Sd' ancora compila, ma la dichiarazione' Sd d' fallisce, quindi va piuttosto bene) – Irfy

+0

@lrfy: Quindi la cosa più semplice da fare è creare un carattere 'is_valid' che combini i vari casi di specializzazione parziale e usalo come il condizionale – Puppy

+0

@Puppy - Ho appena avuto qualcosa di simile anch'io. La tua soluzione 'is_valid' a volte significa scrivere due template, entrambi con tutte le specializzazioni, invece di una sola - e puramente per ottenere un messaggio di errore migliore da quello che vuoi realmente. Potrebbe essere un bel po 'di confusione e duplicare tutti i casi di specializzazione significa che potrebbero facilmente essere incoerenti (anche se AFAICT non dovrebbe mai portare a bug di runtime). Scrivere stranamente la condizione 'static_assert' potrebbe essere un approccio migliore, e probabilmente varrebbe la pena avere un modello' dependent_false '. – Steve314