Si j’ai une variable à l’intérieur d’une fonction (disons un grand tableau), est-il judicieux de la déclarer à la fois static
et constexpr
? constexpr
garantit que le tableau est créé au moment de la compilation, alors le static
serait-il inutile?
void f() { static constexpr int x [] = { // a few thousand elements }; // do something with the array }
Est-ce que la static
fait réellement quelque chose en termes de code généré ou de sémantique?
La réponse courte est que non seulement la static
est utile, mais elle va très bien être désirée.
Tout d’abord, notez que static
et constexpr
sont complètement indépendants l’un de l’autre. static
définit la durée de vie de l’object pendant l’exécution; constexpr
spécifie que l’object doit être disponible lors de la compilation. La compilation et l’exécution sont disjointes et discontinues, à la fois dans le temps et dans l’espace. Donc, une fois le programme compilé, constexpr
n’est plus pertinent.
Chaque variable déclarée constexpr
est implicitement const
mais const
et static
sont presque orthogonaux (sauf pour l’interaction avec static const
entiers static const
).
Le modèle object C++
(§1.9) exige que tous les objects autres que les champs de bits occupent au moins un octet de mémoire et possèdent des adresses; de plus, tous les objects observables dans un programme à un moment donné doivent avoir des adresses distinctes (paragraphe 6). Cela n’exige pas vraiment que le compilateur crée un nouveau tableau sur la stack pour chaque invocation d’une fonction avec un tableau const non statique local, car le compilateur pourrait se réfugier dans le principe as-if
condition qu’il puisse prouver qu’aucun autre object peut être observé.
Cela ne sera pas facile à prouver, malheureusement, à moins que la fonction ne soit sortingviale (par exemple, elle n’appelle aucune autre fonction dont le corps n’est pas visible dans l’unité de traduction) car les tableaux, plus ou moins par définition, sont des adresses. Ainsi, dans la plupart des cas, le tableau const(expr)
non-statique) const(expr)
devra être recréé sur la stack à chaque invocation, ce qui ira à l’encontre de la possibilité de le calculer au moment de la compilation.
D’autre part, un object static const
local est partagé par tous les observateurs, et peut en outre être initialisé même si la fonction dans laquelle il est défini n’est jamais appelée. Donc, rien de ce qui précède ne s’applique, et un compilateur est libre non seulement pour en générer une seule instance; il est libre d’en générer une seule instance dans un stockage en lecture seule.
Vous devez donc absolument utiliser static constexpr
dans votre exemple.
Cependant, il y a un cas où vous ne voudriez pas utiliser static constexper
. À moins qu’un object déclaré constexpr
ne soit utilisé par ODR ou déclaré static
, le compilateur est libre de ne pas l’inclure du tout. C’est très utile, car il permet l’utilisation de tableaux constexpr
temporaires à la constexpr
sans polluer le programme compilé avec des octets inutiles. Dans ce cas, vous ne voudrez manifestement pas utiliser static
, car il est probable que static
provoque l’existence de l’object au moment de l’exécution.