Valore puntatore Constexpr

Sto cercando di dichiarare un puntatore constexpr inizializzato su un valore intero costante, ma clang sta sventando tutti i miei tentativi:

Tentativo 1:

constexpr int* x = reinterpret_cast(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 permettere dal design? Se è così, perché? Se no, come posso farlo?

Nota: gcc accetta tutti questi.

Come nota Luc Danton, i tuoi tentativi sono bloccati dalle regole in [expr.const] / 2 che dicono che varie espressioni non sono permesse nelle espressioni costanti , tra cui:

– un reinterpret_cast
– un’operazione che avrebbe un comportamento indefinito [Nota: incluso […] alcuni parametri aritmetici […] – nota finale]

Il primo punto esclama il tuo primo esempio. Il secondo esempio è escluso dal primo punto sopra, più la regola da [expr.cast] / 4 che:

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

Il secondo punto elenco è stato aggiunto dal numero di nucleo WG21 1313 e chiarisce che l’aritmetica del puntatore su un puntatore nullo non è consentita in un’espressione costante. Questo esclude il tuo terzo esempio.

Anche se queste restrizioni non si applicassero alle espressioni costanti di base, non sarebbe ancora ansible inizializzare un puntatore constexpr con un valore prodotto mediante il cast di un intero, poiché una variabile puntatore constexpr deve essere inizializzata da un’espressione di costante di indirizzo , che, per [ expr.const] / 3, deve valutare a

l’indirizzo di un object 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 applica ancora rigorosamente queste regole, ma le sue versioni recenti si sono avvicinate a loro, quindi dovremmo assumere che alla fine le implementerà pienamente.

Se il tuo objective è dichiarare una variabile per la quale viene eseguita l’inizializzazione statica, puoi semplicemente rilasciare il constexpr – sia clang che g ++ emetteranno un inizializzatore statico per questa espressione. Se hai bisogno che questa espressione faccia parte di un’espressione costante per qualche motivo, hai due possibilità:

  • Ristruttura il tuo codice in modo che un intptr_t sia passato al posto di un puntatore e lo lanci al tipo di puntatore quando è necessario (al di fuori di un’espressione costante), oppure
  • Utilizzare __builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF __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 documentata , non portatile supportata da sia gcc che clang.

La ragione è data dal messaggio di errore (per una volta, molto utile): reinterpret_cast non è consentito in un’espressione costante. È elencato come una delle eccezioni esplicite in 5.19 (paragrafo 2).

Cambiare il reinterpret_cast in un cast in stile C finisce con l’equivalente semantico di reinterpret_cast , quindi non aiuta (e di nuovo il messaggio è molto esplicito).

Se si avesse un modo per ottenere un puntatore con valore 0 si potrebbe effettivamente usare 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 del puntatore come hai fatto tu, o nullptr ) con un valore pari a 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.)