2015-07-09 5 views
19

In C++ 11 è legale di scrivere, per esempio:C'è un modo per inserire un static_assert in un'espressione in ISO C++ 11?

int b = (some_function_returning_void(), 1020); 

e si otterrà indietro 1020. Ma non vi permetterà di scrivere:

int b = (static_assert(2 > 1, "all is lost"), 304); 

Il documentation spiega i punti legali dove può verificarsi static_assert (a keyword, apparentemente):

una dichiarazione asserzione statico può apparire a perimetro blocco (come dichiarazione blocco) e all'interno di un corpo di una classe (come una dichiarazione di membro)

Solo per il gusto di farlo ho provato un paio di cose fino a quando questo ha funzionato:

int b = ({static_assert(2 > 1, "all is lost"); 304;}); 

Ma con -Wpedantic ottengo "warning: ISO C++ forbids braced-groups within expressions". È interessante notare che questi sono chiamati "espressioni di dichiarazione" e used in the Linux kernel.

Ma immaginiamo di voler rimanere -Wpedantic. Esistono soluzioni alternative?

+2

Contesto: Sto cercando di scrivere una macro che funzioni in ANSI C89, ma aggiunge un controllo aggiuntivo se costruita come ISO C++ 11. Sì, sono strano, grazie per avermelo chiesto Oh, quella non era una domanda? Commenta se stai leggendo questo in 9999999999999999999 .... – HostileFork

+1

Puoi inserire l'asser statico all'interno di un'espressione lambda .. '[] {static_assert (..); }(), 1020' – dyp

+0

@dyp Interessante idea ... anche se nella mia nota qui di seguito chiedo quali potrebbero essere le implicazioni di una macro per molte, molte volte ... – HostileFork

risposta

23

Come @dyp accennato nei commenti, si può abusare l'operatore virgola e un lambda-espressione:

([]{static_assert(true,"");}, 42) 

Live on Coliru

+0

Funziona sicuramente! Anche se una domanda che potrei avere è se questa macro è molto usata pesantemente ... come decine di migliaia di volte, c'è un punto in cui il tracciamento di tutti quei lambdas sta gravando sul compilatore? Se esegui una build non ottimizzata, avrai molte entità da monitorare che potrebbero apparire in qualche scenario di debug? – HostileFork

+0

@HostileFork L'espressione lambda crea formalmente un nuovo tipo (ogni volta che si verifica nel codice) e un oggetto da quel nuovo tipo (ogni volta che viene richiamato). Se questo risulta essere un problema, potresti usare un modello di classe? 'template struct sassert {static_assert (cond,"! "); bool statico const value = false; }; (sassert <(2> 1)> :: value && "tutto è perso", 1020) ' – dyp

+0

@dyp Sì, stavo riflettendo su quelle righe ... poiché la creazione di tutti i tipi era la mia preoccupazione) come in un asse non probabile il compilatore è ottimizzato rispetto ai modelli. Ma ci si chiedeva se ci fosse qualcosa di più pulito, e la lambda è davvero più pulita ... – HostileFork

9

static_assert è non un espressione (a differenza sizeof), quindi non è possibile utilizzarlo in cui sarebbe necessaria un'espressione.

Non è nemmeno un'espressione con tipo void (è interessante notare che throw è un'espressione di tipo void) in modo che non si possa nemmeno usarlo in ternario.

Le espressioni di dichiarazione non sono C++ standard, quindi sconsiglio di utilizzarle.

Un lambda

int b = []{ 
    static_assert(2 > 1, "all is lost"); return 304; 
}(); 

o

int b = ([]{static_assert(2 > 1, "all is lost");}, 304); 

è difficilmente pulito. (Il secondo lambda appare come un capello lontano dall'essere indefinito).

+0

Bel suggerimento con i lambda, gente. Per quanto riguarda il secondo, perché sarebbe meno definito di solo '[] {}'? Penserei di non chiamarlo sarebbe più facile da ottimizzare ... – HostileFork

+0

Sono preoccupato per la prima cosa che non è valutabile. L'operatore virgola valuta tutte le espressioni da sinistra a destra. – Bathsheba

+0

È comunque valutabile il valore del lambda, vero? 'auto x = [] {};'? – HostileFork

3

Che dire di un modello di funzione:

template<int T> void my_static_assert() 
{ 
    static_assert(T, "asserted"); 
} 

Poi è possibile utilizzare l'operatore virgola, non è nemmeno necessario chiamare la funzione:

int x = (my_static_assert<(2 > 1)>, 2001); 

Forse avete bisogno di alcune parentesi qua e là per rendere felice il parser. E perdi il messaggio statico, ma funziona.

Problemi correlati