A resposta curta é que não só é static
útil, como sempre será desejável.
Primeiro, observe que static
e constexpr
são completamente independentes um do outro. static
define a vida útil do objeto durante a execução; constexpr
especifica que o objeto deve estar disponível durante a compilação. Compilação e execução são disjuntas e descontínuas, no tempo e no espaço. Assim, uma vez que o programa é compilado, constexpr
não é mais relevante.
Toda variável declarada constexpr
é implicitamente, const
mas const
e static
é quase ortogonal (exceto pela interação com static const
números inteiros).
O C++
modelo de objeto (§1.9) exige que todos os objetos que não sejam campos de bits ocupem pelo menos um byte de memória e tenham endereços; além disso, todos esses objetos observáveis em um programa em um determinado momento devem ter endereços distintos (parágrafo 6). Isso não exige muito que o compilador crie uma nova matriz na pilha para cada chamada de uma função com uma matriz const não estática local, porque o compilador pode se refugiar no as-if
princípio, desde que possa provar que nenhum outro objeto desse tipo pode ser observado.
Infelizmente, isso não será fácil de provar, a menos que a função seja trivial (por exemplo, não chame nenhuma outra função cujo corpo não seja visível na unidade de tradução) porque matrizes, mais ou menos por definição, são endereços. Portanto, na maioria dos casos, a const(expr)
matriz não estática precisará ser recriada na pilha a cada chamada, o que anula o ponto de poder computá-la em tempo de compilação.
Por outro lado, um static const
objeto local é compartilhado por todos os observadores e, além disso, pode ser inicializado mesmo que a função na qual ele é definido nunca seja chamada. Portanto, nenhuma das opções acima se aplica, e um compilador é livre não apenas para gerar apenas uma única instância dele; é gratuito gerar uma única instância dele no armazenamento somente leitura.
Então você definitivamente deve usar static constexpr
no seu exemplo.
No entanto, há um caso em que você não gostaria de usar static constexpr
. A menos que um constexpr
objeto declarado seja usado ou declarado por ODRstatic
, o compilador é livre para não incluí-lo. Isso é bastante útil, pois permite o uso de constexpr
matrizes temporárias em tempo de compilação sem poluir o programa compilado com bytes desnecessários. Nesse caso, você claramente não gostaria de usar static
, pois static
é provável que force o objeto a existir no tempo de execução.
const
de umconst
objeto, apenas de umconst X*
que aponte para umX
. Mas esse não é o ponto; o ponto é que objetos automáticos não podem ter endereços estáticos. Como eu disse,constexpr
deixa de ser significativo uma vez que a compilação estiver concluída, então não há nada de deitar fora (e muito possivelmente nada, porque o objeto não é ainda garantida a existir em tempo de execução.)static
econstexpr
, mas explicar que eles são ortogonais e independente, fazendo coisas diferentes. Você menciona um motivo para NÃO combinar os dois, pois isso ignoraria o uso do ODR (o que parece útil). Ah, e ainda não entendo por que a estática deve ser usada com constexpr, pois estática é para coisas de tempo de execução. Você nunca explicou por que a estática no constexpr é importante.static constexpr
(isso evita que a matriz constante seja recriada a cada chamada de função), mas ajustei algumas palavras que podem torná-lo mais claro. Obrigado.constexpr
variável constante é usada apenas em contextos de tempo de compilação e nunca é necessária no tempo de execução,static
não faz sentido, pois no momento em que você acessa o tempo de execução, o valor foi efetivamente "incorporado". No entanto, seconstexpr
for usado em contextos de tempo de execução (em outras palavras,constexpr
precisaria ser convertido emconst
implicitamente e disponível com um endereço físico para código de tempo de execução), ele desejarástatic
garantir a conformidade com o ODR, etc. Esse é o meu entendimento, pelo menos.static constexpr int foo = 100;
. Não há razão para que o compilador não possa substituirfoo
literalmente o uso de qualquer lugar100
, a menos que o código esteja fazendo algo parecido&foo
. Então,static
nofoo
tem nenhuma utilidade, neste caso, uma vez quefoo
não existe em tempo de execução. Novamente, tudo depende do compilador.Além da resposta dada, vale a pena notar que o compilador não precisa inicializar a
constexpr
variável no momento da compilação, sabendo que a diferença entreconstexpr
estatic constexpr
é a sua utilizaçãostatic constexpr
garante que a variável seja inicializada apenas uma vez.O código a seguir demonstra como a
constexpr
variável é inicializada várias vezes (embora com o mesmo valor), enquantostatic constexpr
certamente é inicializada apenas uma vez.Além disso, o código compara a vantagem de
constexpr
contraconst
em combinação comstatic
.Saída possível do programa:
Como você pode ver, ele
constexpr
é iniciado várias vezes (o endereço não é o mesmo), enquanto astatic
palavra-chave garante que a inicialização seja realizada apenas uma vez.fonte
constexpr const short constexpr_short
para dar erro se constexpr_short for inicializado novamenteconstexpr const
não faz sentido, porqueconstexpr
já éconst
, adicionarconst
uma ou várias vezes é ignorado pelo compilador. Você está tentando capturar um erro, mas não é um erro, é assim que a maioria dos compiladores funciona.