2015-06-11 13 views
12

Si consideri il seguente codice:static_assert dipende modello di classe

template <unsigned int N> 
struct myclass 
{ 
    unsigned int f() {return N;} 
    unsigned int g() {static_assert(N > 0, ""); return N-1;} 
}; 

Domanda: ho la garanzia che il seguente codice compilerà:

myclass<0> c; 
c.f(); 

Ma quanto segue non:

myclass<0> c; 
c.f(); 
c.g(); 
+0

Certo, il primo non un'istanza di 'g' (inoltre, la natura privata delle funzioni) –

+0

@ DieterLücking Classe modificata in struct. – Vincent

+0

@Vincent f() deve essere reso pubblico così come g() –

risposta

11

Sì, avete questa garanzia. Da [temp.inst]/11, corsivo mio:

L'attuazione non deve implicitamente istanziare una funzione di modello, un modello variabile, un modello di membro, una funzione di membro non virtuale, un membro classe, o membro di dati statici di un modello di classe che non richiede l'istanziazione.

Se non si chiama g(), non richiede di un'istanza, quindi non ci dovrebbero essere problemi di chiamata myclass<0>{}.f().

Questa è la stessa garanzia che consente di utilizzare std::vector e std::map con i tipi non predefiniti costruibili fino a quando non fai le cose come chiamata resize() e operator[], rispettivamente.

un follow-up, come Jarod42 points out, è che un'istanza esplicitamente myclass<0> produrrà l'asserzione perché, da [temp.explicit]/8:

un'istanza esplicita che i nomi di un modello di classe di specializzazione è anche un esplicito istanza dello stesso tipo (dichiarazione o definizione) di ciascuno dei suoi membri (esclusi i membri ereditati dalla base classi e membri che sono modelli) che non è stato precedentemente esplicitamente specializzato nella unità di conversione contenente l'istanza esplicata n, ad eccezione di quanto descritto di seguito.

Le eccezioni non si applicano qui.

+1

Nota che si specifica esplicitamente 'myclass <0>' ('template struct myclass <0>;') produrrà l'asserzione. – Jarod42

+0

Pedantic: "si dispone di quella garanzia" modulo la solita dichiarazione di non responsabilità che lo standard richiede solo un messaggio diagnostico quando si attiva un'asserzione statica e non richiede il fallimento della compilazione. –

+0

@Barry: hai un esempio di come posso fare fallire la compilazione utilizzando resize() su un vettore per un tipo che non è predefinito costruibile? – Vincent

-1

Se si desidera disabilitare la funzione in fase di compilazione, è necessario utilizzare enable_if invece di static_assert

template<unsigned int N> 
struct Foo { 
    unsigned int f() {} 
    enable_if_t<(N > 0), unsigned int> g() {} 
}; 

Foo<0> t{}; 
t.f(); /// this is okay and will compile 
// t.g() if I uncomment this line, it will not compile anymore. 
+0

Non necessariamente. L'utilizzo di enable_if qui sopra non è corretto per una cosa, in quanto devi essere in un contesto basato su modelli per farlo funzionare. Anche trasformandolo in una funzione membro basata su modelli, enable_if è in realtà per aggiungere/rimuovere qualcosa al set candidato, invece di voler sempre un errore grave quando si tenta di invocare. – Nevin

+0

Questo non verrà compilato, l'abilitazione se non si trova in un contesto in cui si applica SFINAE, quindi è semplicemente un errore grave. – Barry

0

Utilizzare un modello di specializzazione:

template <unsigned N> 
struct myclass 
{ 
    unsigned f() { return N; } 
    unsigned g() { return N-1; } 
}; 

template <> 
struct myclass <0> 
{ 
    unsigned f() { return 0; } 
}; 
+0

Questo è il modo giusto se hai bisogno di un'istanza esplicita, ma anche di un dolore perché tutti gli altri membri devono essere duplicati. –

+0

@BenVoigt Vero, ma penso che in pratica i modelli di classe progettati per applicare i vincoli non contengano (e non dovrebbero) molto altro. – KevinZ

Problemi correlati