2010-05-25 4 views
5

Gli asserti statici sono molto utili per controllare le cose in fase di compilazione. Un semplice assert linguaggio statico simile a questa:asser statico per variabili const?

template<bool> struct StaticAssert; 
template<> struct StaticAssert<true> {}; 

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0) 

Questo è un bene per cose come

STATIC_ASSERT(sizeof(float) == 4) 

e:

#define THIS_LIMIT (1000) 
... 
STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT); 

Ma usando #define non è il modo "C++" di definire costanti. C++ avrebbe si utilizza un namespace anonimo:

namespace { 
    const int THIS_LIMIT = 1000; 
} 

o anche:

static const int THIS_LIMIT = 1000; 

Il problema di questo è che con un const int non è possibile utilizzare STATIC_ASSERT() e si deve ricorrere a un run-time controlla quale è stupido.

C'è un modo per risolvere correttamente questo in C++ corrente?
Credo di aver letto C++ 0x ha qualche possibilità di fare questo ...


EDIT

Ok quindi questo

static const int THIS_LIMIT = 1000; 
... 
STATIC_ASSERT(THIS_LIMIT > 0); 

compila bene
Ma this:

static const float THIS_LIMIT = 1000.0f; 
... 
STATIC_ASSERT(THIS_LIMIT > 0.0f); 

no.
(in Visual Studio 2008)

Come mai?

+0

Perché stai utilizzando l'asserzione statica NIH, invece di BOOST_STATIC_ASSERT? http://www.boost.org/doc/libs/1_43_0/doc/html/boost_staticassert.html –

+0

Non riesco a usare boost (ancora) per qualche ragione aziendale stupida – shoosh

+1

Cosa ti fa pensare che non puoi usare costanti integrali in questo caso? Quanto sopra dovrebbe funzionare bene. –

risposta

10

Perché, si può ancora affermare statico con const int:

#define static_assert(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])] 
static_assert(THIS_LIMIT > OTHER_LIMIT) 

Inoltre, use boost!

BOOST_STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT) 

... Avrai un sacco messaggi di errore più bello ...

+0

Beh, c'è una lezione per me. non dire che qualcosa non è possibile prima di provarlo ... – shoosh

+0

Mi chiedo ancora quale problema dovrebbe risolvere? –

+0

@shoosh: il codice originale deve essere compilato correttamente. Vedi [mia risposta] (http://stackoverflow.com/questions/2902917/2903013#2903013). – sbi

1

Forse stai confondendo il comportamento C++ 's con C dove const int non rappresenta una vera e propria costante fase di compilazione. O forse il tuo compilatore C++ è rotto. Se è veramente quest'ultimo, utilizzare invece enum.

+0

hai +1, ho -1 per la stessa soluzione =/ –

+0

@Viktor Sehr: Per essere onesti, la mia risposta fornisce una spiegazione più che la tua, e l'uso di 'enum' dovrebbe * non * essere necessario in C++ per questo caso. – jamesdlin

+0

@ViktorSehr: questo posto non riguarda la rimozione di "soluzioni" in frammenti di codice come se fossero pezzi di carne; si tratta di scrivere _answers_ per spiegare, insegnare e informare. Spesso, le buone risposte includono illustrazioni di codice, ma questo non significa che una risposta che consiste in _solamente_ di codice è buona. In effetti, è raro che sia così. –

1

questo:

namespace { 
    const int THIS_LIMIT = 1000; 
} 

template<bool> struct StaticAssert; 
template<> struct StaticAssert<true> {}; 

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0) 

int main() 
{ 
    STATIC_ASSERT(THIS_LIMIT > 5); 

    return (0); 
} 

compila bene con VC e Comeau.

0

enum{THIS_LIMIT = 1000};

+0

Perché il voto -1? –

+1

Non ti ho minimizzato, ma questa non è una risposta alla domanda data. È una soluzione valida, ed è un codice valido, ma hai fornito la descrizione zero, la spiegazione zero e l'analisi zero di (a) che cosa fa, (b) in che modo differisce dal codice dell'OP e (c) perché dovrebbe essere usato (e , infatti, non è necessario essere). Di conseguenza si presenta come un po 'pigro, e questo è probabilmente il motivo per cui è stato downvoted. In effetti, vieni a pensarci, lo farò a bassa voce anche per questo motivo. Scusate. –

+0

Non ti preoccupare, penso che tu abbia fornito una buona spiegazione :) –

4

static_assert è una caratteristica del compilatore in C++ 0x così finché hai un compilatore relativamente up-to-date è possibile utilizzare tale.Attenzione per fare #define static_assert(x) ..., perché è una vera parola chiave in C++ 0x in modo da nascondere la funzionalità del compilatore in modo permanente. Inoltre, C++ 0x static_assert accetta due parametri (ad esempio static_assert(sizeof(int) == 4, "Expecting int to be 4 bytes")), quindi potresti causare problemi a te stesso provando a passare in futuro se usi quel #define.

2

Sembra che tu sia davvero chiedono perché il seguente è il caso (e posso confermare che sia GCC 4.3.4 e Visual C++ 2008 Express):

template<bool> struct StaticAssert; 
template<> struct StaticAssert<true> {}; 

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0) 


static const int AN_INT = 1000; 
static const float A_FLOAT = 1000.0f; 

int main() 
{ 
    STATIC_ASSERT(AN_INT > 0);  // OK 
    STATIC_ASSERT(A_FLOAT > 0.0f); // Error: A_FLOAT may not appear in a constant expression 
} 

ci sono il numero di restrizioni sull'uso statico di valori a virgola mobile. Nota, ad esempio, che non puoi passarli come argomenti del template. Questo perché:

[C++11: 5.19/2]:A condizionale espressione- è un nucleo un'espressione costante meno che coinvolge uno dei seguenti come sottoespressione potenzialmente valutata (3.2), ma sottoespressioni di AND logico (5.14), logica Le operazioni OR (5.15) e condizionali (5.16) non valutate non sono considerate [Nota: Un operatore sovraccarico richiama una funzione . -end nota] :

  • [..]
  • un lvalue-to-rvalue di conversione (4.1) a meno che non viene applicata a
    • un glvalue di integrale o di enumerazione digitare che fa riferimento a un oggetto const non volatile con un'inizializzazione precedente, inizializzata con un'espressione costante o
    • un valore glaciale di tipo letterale che fa riferimento a un oggetto non volatile definito con constexpr o che si riferisce a un sottooggetto di tale oggetto o
    • un glivalue di tipo letterale che fa riferimento a un oggetto temporaneo non volatile la cui durata non è terminata, inizializzata con una costante espressione;
  • [..]

(cioè solo tipi integrali e di enumerazione sono consentiti;. Nessun tipi a virgola mobile)

quanto riguarda il motivo per questa regola, I Non sono del tutto sicuro, ma il seguente tipo di logica potrebbe avere qualcosa a che fare con questo:

[C++11: 5.19/4]: [..] Poiché questo standard internazionale non impone restrizioni sulla precisione dello delle operazioni in virgola mobile, non è specificato se la valutazione di un'espressione in virgola mobile durante la conversione produce lo stesso risultato della valutazione della stessa espressione (o le stesse operazioni sugli stessi valori) durante l'esecuzione del programma. [..]