La risposta breve è che non solo è static
utile, è abbastanza bene sarà sempre desiderato.
Innanzitutto, notare che static
e constexpr
sono completamente indipendenti l'uno dall'altro. static
definisce la durata dell'oggetto durante l'esecuzione; constexpr
specifica che l'oggetto deve essere disponibile durante la compilazione. La compilazione e l'esecuzione sono disgiunte e discontinue, sia nel tempo che nello spazio. Quindi, una volta che il programma è stato compilato, constexpr
non è più rilevante.
Ogni variabile dichiarata constexpr
è implicitamente const
ma const
e static
sono quasi ortogonali (tranne che per l'interazione con static const
numeri interi.)
Il modello C++
oggetti (§ 1.9) richiede che tutti gli oggetti diversi bit-field occupano almeno un byte di memoria e indirizzi; inoltre tutti questi oggetti osservabili in un programma in un dato momento devono avere indirizzi distinti (paragrafo 6). Questo non richiede al compilatore di creare una nuova matrice sullo stack per ogni richiamo di una funzione con un array const non statico locale, in quanto il compilatore potrebbe trovare rifugio nel principio as-if
a condizione che provi che nessun altro oggetto di questo tipo può essere osservato
Questo non sarà facile da provare, sfortunatamente, a meno che la funzione non sia banale (ad esempio, non chiama nessuna altra funzione il cui corpo non è visibile all'interno dell'unità di traduzione) perché gli array, più o meno per definizione, sono indirizzi. Pertanto, nella maggior parte dei casi, la matrice non statica const(expr)
dovrà essere ricreata nello stack ad ogni richiamo, il che vanifica il punto di essere in grado di calcolarlo in fase di compilazione.
D'altra parte, un oggetto locale static const
è condiviso da tutti gli osservatori e inoltre può essere inizializzato anche se la funzione in cui è definita non viene mai chiamata. Quindi, nessuno dei precedenti si applica e un compilatore è libero non solo di generare solo una singola istanza di esso; è libero di generare una singola istanza in memoria di sola lettura.
Quindi dovresti usare sicuramente static constexpr
nel tuo esempio.
Tuttavia, vi è un caso in cui non si desidera utilizzare static constexper
. A meno che un oggetto dichiarato constexpr
sia ODR-usato o dichiarato static
, il compilatore è libero di non includerlo affatto. È piuttosto utile, perché consente l'utilizzo di array temporanei constexpr
temporanei senza eseguire il polling del programma compilato con byte non necessari. In tal caso, chiaramente non si desidera utilizzare static
, poiché è probabile che lo static
imponga l'esistenza dell'oggetto in fase di esecuzione.
'constexpr' non garantisce nulla in fase di compilazione, il compilatore è libero di valutare le cose' constexpr' in fase di runtime. È solo costretto a valutare qualcosa in fase di compilazione se si utilizza quel qualcosa in contesti in cui è necessario essere conosciuto in fase di compilazione. – Praetorian
Credo che @Praetorian sia corretto, e 'static' garantirà non solo che è in fase di compilazione, ma che è memorizzato solo con le costanti di tempo di compilazione. Penso che senza 'static' sarebbe _ teoricamente_ conforme a spingere la matrice (enorme) sullo stack ad ogni invocazione della funzione. –
@AndrewLazarus, non solo è teoricamente conforme per spingere la matrice nello stack ad ogni invocazione, è teoricamente richiesto (modulo la regola as-if). In pratica, nella mia esperienza, succede sempre molto bene. Vedi la mia risposta per maggiori dettagli. – rici