2012-04-29 15 views
22

Sto cercando di dichiarare un puntatore constexpr inizializzato a un valore intero costante, ma clang è sventare tutti i miei tentativi:Constexpr valore del puntatore

Tentativo 1:

constexpr int* x = reinterpret_cast<int*>(0xFF); 

test.cpp:1:20: note: reinterpret_cast is not allowed in a constant expression 

Tentativo 2:

constexpr int* x = (int*)0xFF; 

test.cpp:1:20: note: cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression 

Tentativo 3:

constexpr int* x = (int*)0 + 0xFF; 

test.cpp:1:28: note: cannot perform pointer arithmetic on null pointer 

È ciò che sto cercando di non consentire per progettazione? Se è così, perché? Se no, come posso farlo?

Nota: gcc accetta tutto ciò.

+2

Perché avete bisogno di un constexpr qui? Non è effettivamente constexpr lo stesso di const se non si sta utilizzando una funzione? –

+0

@RobertMason: Beh, ad esempio, se è un membro statico di una classe e non è constexpr, non posso inizializzarlo in linea. – HighCommander4

+1

Forse una funzione membro in linea statica sarebbe più appropriata di un membro dati. –

risposta

18

Come nota Luc Danton, i tuoi tentativi sono bloccati dalle regole in [expr.const]/2 che dicono che varie espressioni non sono consentite nella costante di core espressioni, tra cui:

- un reinterpret_cast
- un'operazione che avrebbe un comportamento indefinito [Nota: tra cui [...] certo l'aritmetica dei puntatori [...] - end nota]

Il la prima pallottola esclude il tuo primo esempio. Il secondo esempio è esclusa dal primo proiettile sopra, più la regola da [expr.cast]/4 che:

Le conversioni eseguite da [...] un reinterpret_cast [...] possono essere eseguite utilizzando la notazione cast di conversione di tipo esplicita. Si applicano le stesse restrizioni e comportamenti semantici.

Il secondo proiettile è stato aggiunto da WG21 core issue 1313, e chiarisce che puntatori su un puntatore nullo non è consentito in un'espressione costante. Questo esclude il tuo terzo esempio.

Anche se queste restrizioni non si applicano alle espressioni costanti del core, non sarebbe comunque possibile inizializzare un puntatore constexpr con un valore prodotto per fusione un numero intero, poiché una variabile puntatore constexpr deve essere inizializzato un indirizzo espressione costante, che, di [expr.const]/3, deve valutare su

l'indirizzo di un oggetto con durata di memorizzazione statica, l'indirizzo di una funzione o un valore di puntatore nullo.

Un cast intero per il tipo di puntatore non è uno di questi.

g ++ non è ancora rigorosamente rispettare queste regole, ma le sue recenti uscite sono state sempre più vicino a loro, quindi dovremmo supporre che alla fine loro piena attuazione.

Se l'obiettivo è dichiarare una variabile per la quale viene eseguita l'inizializzazione statica, è sufficiente rilasciare lo constexpr - sia clang che g ++ emetteranno un inizializzatore statico per questa espressione. Se avete bisogno di questa espressione di far parte di una costante espressione per qualche motivo, si hanno due scelte:

  • Ristrutturare il codice in modo che un intptr_t viene passato attorno al posto di un puntatore, e lanci di tipo puntatore quando si necessario (al di fuori di un'espressione costante) o
  • Utilizzare __builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF. Questa esatta forma di espressione (con __builtin_constant_p sul lato sinistro di un operatore condizionale) disabilita il controllo delle espressioni costanti nei bracci dell'operatore condizionale ed è un'estensione GNU poco nota, ma documented, supportata da sia gcc che clang.
4

Il motivo è quello indicato dal (per una volta, molto utile) messaggio di errore: reinterpret_cast non è consentito in un'espressione costante. È elencato come una delle eccezioni esplicite in 5.19 (paragrafo 2).

La modifica di reinterpret_cast in un cast di tipo C termina con l'equivalente semantico di reinterpret_cast, quindi non è di aiuto (e anche in questo caso il messaggio è molto esplicito).

Se tu avessi un modo per ottenere un puntatore con un valore 0 si potrebbe effettivamente utilizzare p + 0xff ma non riesco a pensare ad un modo per ottenere un tale puntatore con un'espressione costante. Potresti aver fatto affidamento sul valore del puntatore nullo (0 in un contesto di puntatore come hai fatto tu, o nullptr) con un valore di 0 sulla tua implementazione ma, come hai visto tu stesso, la tua implementazione si rifiuta di farlo. Penso che sia permesso farlo. (Ad esempio, le implementazioni possono essere salvate per la maggior parte delle espressioni costanti.)

+1

e dovrebbe essere '0xff/sizeof (* x)' che aggiunge. –

Problemi correlati