Constant expressions
Définit une expression qui peut être évaluée à la compilation.
De telles expressions peuvent être utilisées comme arguments de template constants, tailles de tableaux, et dans d'autres contextes nécessitant des expressions constantes, par exemple.
int n = 1; std::array<int, n> a1; // Erreur : « n » n'est pas une expression constante const int cn = 2; std::array<int, cn> a2; // OK : « cn » est une expression constante
Définition
|
Une expression qui appartient à l'une des catégories d'expressions constantes listées ci-dessous est une expression constante .
|
(jusqu'à C++11) | ||
|
Les expressions suivantes sont collectivement appelées expressions constantes :
|
(depuis C++11)
(jusqu'à C++14) |
||
|
Les entités suivantes sont des résultats autorisés d'une expression constante :
Une expression constante est soit une glvalue expression constante fondamentale qui se réfère à une entité qui est un résultat autorisé d'une expression constante, soit une prvalue expression constante fondamentale dont la valeur satisfait aux contraintes suivantes :
|
(depuis C++14)
(jusqu'à C++26) |
||
|
Une expression constante est soit une glvalue expression constante de base qui réfère à un objet ou une fonction non- immédiate , soit une prvalue expression constante de base dont la valeur satisfait les contraintes suivantes :
|
(depuis C++26) |
Lors de la détermination si une expression est une expression constante, l'élision de copie est supposée ne pas être effectuée.
La définition C++98 des expressions constantes se trouve entièrement dans la boîte repliable. La description suivante s'applique à C++11 et aux versions ultérieures de C++.
Type littéral
Les types suivants sont collectivement appelés types littéraux :
- éventuellement qualifié cv void
- type scalaire
- type référence
- un tableau de type littéral
- type de classe éventuellement qualifié cv qui satisfait toutes les conditions suivantes :
-
- Il possède un destructeur trivial (jusqu'en C++20) constexpr destructeur (depuis C++20) .
- Tous ses membres de données non statiques non-variants et classes de base sont de types littéraux non-volatils.
- C'est l'un des types suivants :
|
(depuis C++17) |
-
-
- un type union agrégé qui satisfait l'une des conditions suivantes :
-
- Il n'a pas de membre variant .
- Il a au moins un membre variant de type littéral non volatile.
- un type agrégé non union, et chacun de ses membres union anonyme satisfait l'une des conditions suivantes :
-
- Il n'a pas de membre variant.
- Il a au moins un membre variant de type littéral non volatile.
- un type avec au moins un constexpr constructeur (template) qui n'est pas un constructeur de copie ou de déplacement
-
Seuls les objets de types littéraux peuvent être créés dans une expression constante.
Expression constante de base
Une expression constante de base est toute expression dont l'évaluation ne devrait pas évaluer l'une quelconque des constructions de langage suivantes :
| Constructe de langage | Version | Document(s) |
|---|---|---|
le pointeur
this
, sauf dans une
constexpr
fonction
évaluée dans le cadre de l'expression, ou lorsqu'il apparaît dans une expression d'accès membre de classe implicite ou explicite
|
N2235 | |
| un flux de contrôle qui traverse une déclaration d'une variable de bloc avec une durée de stockage statique ou thread qui n'est pas utilisable dans les expressions constantes | (depuis C++23) | P2242R3 |
|
Cette section est incomplète
Motif : Transférer le contenu de la liste ordonnée HTML brute ci-dessous vers le tableau wiki ci-dessus, tout en ajoutant les documents/problèmes CWG qui ont introduit l'élément correspondant dans la norme. Les mini-exemples ne sont pas conservés, ils peuvent être combinés pour former un exemple plus large au bas de cette page. |
-
a function call expression that calls a function (or a constructor) that is not declared
constexpr
constexpr int n = std::numeric_limits<int>::max(); // OK : max() est constexpr constexpr int m = std::time(nullptr); // Erreur : std::time() n'est pas constexpr
- a function call to a constexpr function which is declared, but not defined
- a function call to a constexpr function/constructor template instantiation where the instantiation fails to satisfy fonction/constructeur constexpr requirements.
- a function call to a constexpr virtual function, invoked on an object whose dynamic type is constexpr-unknown
- an expression that would exceed the implementation-defined limits
-
an expression whose evaluation leads to any form of core language
indéfini
ou erroné
(depuis C++26)
behavior, except for any potential undefined behavior introduced by
attributs standard
.
constexpr double d1 = 2.0 / 1.0; // OK constexpr double d2 = 2.0 / 0.0; // Erreur : non défini constexpr int n = std::numeric_limits<int>::max() + 1; // Erreur : dépassement int x, y, z[30]; constexpr auto e1 = &y - &x; // Erreur : indéfini constexpr auto e2 = &z[20] - &z[3]; // OK constexpr std::bitset<2> a; constexpr bool b = a[2]; // Comportement indéfini, mais non spécifié si détecté
- (jusqu'à C++17) a expression lambda
-
an lvalue-to-rvalue
conversion implicite
unless applied to...
- une glvalue de type (éventuellement qualifié cv) std::nullptr_t
-
une glvalue de type littéral non volatile qui désigne un objet
utilisable dans les expressions constantes
int main() { const std::size_t tabsize = 50; int tab[tabsize]; // OK: tabsize est une expression constante // car tabsize est utilisable dans les expressions constantes // car il a un type intégral qualifié const, et // son initialiseur est un initialiseur constant std::size_t n = 50; const std::size_t sz = n; int tab2[sz]; // Erreur: sz n'est pas une expression constante // car sz n'est pas utilisable dans les expressions constantes // car son initialiseur n'était pas un initialiseur constant }
- une glvalue de type littéral non volatile qui fait référence à un objet non volatile dont la durée de vie a commencé durant l'évaluation de cette expression
T*
sauf si le pointeur contient une valeur de pointeur nul ou pointe vers un objet dont le type est
similaire
à
T
(depuis C++26)
dynamic_cast
dont l'opérande est une glvalue qui fait référence à un objet dont le type dynamique est constexpr-inconnu
(depuis C++20)
reinterpret_cast
constexpr int incr(int& n) { return ++n; } constexpr int g(int k) { constexpr int x = incr(k); // Erreur : incr(k) n'est pas une expression constante de base // car la durée de vie de k // a commencé en dehors de l'expression incr(k) return x; } constexpr int h(int k) { int x = incr(k); // OK : x n'est pas requis d'être initialisé // avec une expression constante de base return x; } constexpr int y = h(1); // OK : initialise y avec la valeur 2 // h(1) est une expression constante de base car // la durée de vie de k commence à l'intérieur de l'expression h(1)
typeid
expression applied to a glvalue of polymorphic type
et que cette glvalue fait référence à un objet dont le type dynamique est constexpr-inconnu
(depuis C++20)
|
(depuis C++20) |
|
(depuis C++26) |
constexpr void check(int i) { if (i < 0) throw i; } constexpr bool is_ok(int i) { try { check(i); } catch (...) { return false; } return true; } constexpr bool always_throw() { throw 12; return true; } static_assert(is_ok(5)); // OK static_assert(!is_ok(-1)); // OK depuis C++26 static_assert(always_throw()); // Erreur : exception non capturée
goto
dynamic_cast
ou
typeid
ou une expression
new
(depuis C++26)
qui lancerait une exception
où aucune définition du type d'exception n'est accessible
(depuis C++26)
void g() { const int n = 0; constexpr int j = *&n; // OK : en dehors d'une expression lambda [=] { constexpr int i = n; // OK : 'n' n'est pas odr-used et n'est pas capturé ici constexpr int j = *&n; // Mal formé : '&n' serait une odr-use de 'n' }; }
|
notez que si l'odr-use a lieu dans un appel de fonction à une closure, il ne se réfère pas à this ou à une variable englobante, car il accède à un membre de données de la closure à la place // OK : 'v' & 'm' sont odr-used mais n'apparaissent pas dans une expression constante // dans la lambda imbriquée auto monad = [](auto v){ return [=]{ return v; }; }; auto bind = [](auto m){ return [=](auto fvm){ return fvm(m()); }; }; // OK d'avoir des captures vers des objets automatiques créés durant l'évaluation d'expression constante static_assert(bind(monad(2))(monad)() == monad(2)()); |
(depuis C++17) |
Exigences supplémentaires
Même si une expression E n'évalue rien de ce qui est mentionné ci-dessus, il est défini par l'implémentation si E est une expression constante de base si l'évaluation de E entraînerait un comportement indéfini à l'exécution .
Même si une expression E n'évalue rien de ce qui est mentionné ci-dessus, il n'est pas spécifié si E est une expression constante de base si l'évaluation de E évaluerait l'un des éléments suivants :
- Une opération avec un comportement non défini dans la bibliothèque standard .
- Un appel de la macro va_start .
Pour déterminer si une expression est une expression constante de base, l'évaluation du corps d'une fonction membre de
std::
allocator
<
T
>
est ignorée si
T
est un type littéral.
Aux fins de déterminer si une expression est une expression constante de base, l'évaluation d'un appel à un constructeur de copie/déplacement trivial ou à un opérateur d'affectation de copie/déplacement d'une union est considérée comme copiant/déplaçant le membre actif de l'union, s'il existe.
|
Pour déterminer si une expression est une expression constante de base, l'évaluation d'une expression d'identifiant qui nomme une liaison structurée bd a la sémantique suivante :
|
(depuis C++26) |
Lors de l'évaluation de l'expression en tant qu'expression constante de base, toutes les expressions d'identificateur et les utilisations de * this qui se réfèrent à un objet ou une référence dont la durée de vie a commencé en dehors de l'évaluation de l'expression sont traitées comme se référant à une instance spécifique de cet objet ou de cette référence dont la durée de vie et celle de tous les sous-objets (y compris tous les membres d'union) inclut l'ensemble de l'évaluation constante.
- Pour un tel objet qui n'est pas utilisable dans les expressions constantes (depuis C++20) , le type dynamique de l'objet est constexpr-unknown .
- Pour une telle référence qui n'est pas utilisable dans les expressions constantes (depuis C++20) , la référence est traitée comme liée à un objet non spécifié du type référencé dont la durée de vie et celle de tous les sous-objets inclut l'ensemble de l'évaluation constante et dont le type dynamique est constexpr-unknown.
Expression constante entière
Expression constante entière est une expression de type entier ou de type énumération non-scopée implicitement convertie en prvalue, où l'expression convertie est une expression constante de base.
Si une expression de type classe est utilisée là où une expression constante intégrale est attendue, l'expression est implicitement convertie contextuellement en un type intégral ou énumération non délimitée.
Expression constante convertie
Une
expression constante convertie
de type
T
est une expression
implicitement convertie
vers le type
T
, où l'expression convertie est une expression constante, et la séquence de conversion implicite contient seulement :
-
- constexpr conversions définies par l'utilisateur
- conversions lvalue-vers-rvalue
- promotions intégrales
- non-rétrécissantes conversions intégrales
- promotions en virgule flottante
- non-rétrécissantes conversions en virgule flottante
| (depuis C++17) |
Et si une liaison de référence a lieu, elle ne peut être qu'une liaison directe .
Les contextes suivants nécessitent une expression constante convertie :
- l' constant-expression des case labels
- enumerator initializers lorsque le type sous-jacent est fixe
- arguments de template (until C++17) constants template arguments entiers et énumérés
|
(depuis C++14) |
|
(depuis C++26) |
Une expression constante contextuellement convertie de type bool est une expression, contextuellement convertie en bool , où l'expression convertie est une expression constante et la séquence de conversion contient uniquement les conversions mentionnées ci-dessus.
Les contextes suivants nécessitent une expression constante convertie contextuellement de type bool :
| (jusqu'en C++23) | |
|
(depuis C++17)
(jusqu'en C++23) |
|
| (depuis C++20) |
Entités constitutivesLes valeurs constitutives d'un objet obj sont définies comme suit :
Les références constitutives d'un objet obj incluent les références suivantes :
Les valeurs constitutives et références constitutives d'une variable var sont définies comme suit :
Pour toute référence constitutive ref d'une variable var , si ref est liée à un objet temporaire ou à un sous-objet de celui-ci dont la durée de vie est étendue à celle de ref , les valeurs et références constitutives de cet objet temporaire sont également des valeurs et références constitutives de var , récursivement. Entités représentables en constexprLes objets avec une durée de vie statique sont référençables en constexpr à tout point du programme.
Un objet
obj
avec une durée de vie automatique est
référençable en constexpr
à partir d'un point
Un objet ou une référence
x
est
représentable en constexpr
à un point
|
(depuis C++26) | ||||||||
Entités à initialisation constante
Utilisable dans les expressions constantesUne variable est potentiellement-constante si elle est une constexpr variable ou si elle a un type référence ou un type entier ou énumération qualifié const non volatile.
Une variable potentiellement constante initialisée de manière constante
var
est
utilisable dans les expressions constantes
à un point
Expressions manifestement évaluées de manière constanteLes expressions suivantes (y compris les conversions vers le type de destination) sont manifestement évaluées de manière constante :
Le fait qu'une évaluation se produise dans un contexte manifestement constant peut être détecté par
std::is_constant_evaluated
et
|
(depuis C++20) |
Fonctions et variables nécessaires pour l'évaluation constante
Les expressions ou conversions suivantes sont potentiellement évaluées de manière constante :
- expressions manifestement évaluées constantes
- expressions potentiellement évaluées
- sous-expressions immédiates d'un initialiseur entre accolades (l'évaluation constante peut être nécessaire pour déterminer si une conversion est rétrécissante )
- expressions d'adressage qui apparaissent dans une entité template (l'évaluation constante peut être nécessaire pour déterminer si une telle expression est dépendante en valeur )
- sous-expressions de l'un des éléments ci-dessus qui ne sont pas des sous-expressions d'un opérande non évalué imbriqué
Une fonction est nécessaire pour l'évaluation constante si c'est une fonction constexpr et nommée par une expression potentiellement évaluée de manière constante.
Une variable est nécessaire pour l'évaluation constante si elle est soit une variable constexpr, soit de type intégral qualifié const non volatile ou de type référence, et que l' expression d'identifiant qui la désigne est potentiellement évaluée de manière constante.
Définition d'une fonction par défaut et instanciation d'une function template specialization ou variable template specialization (since C++14) sont déclenchées si la fonction ou variable (since C++14) est nécessaire pour l'évaluation constante.
Sous-expression constante
Une sous-expression constante est une expression dont l'évaluation en tant que sous-expression d'une expression e n'empêcherait pas e d'être une expression constante fondamentale , où e n'est aucune des expressions suivantes :
| (depuis C++20) |
Notes
| Macro de test de fonctionnalité | Valeur | Std | Fonctionnalité |
|---|---|---|---|
__cpp_constexpr_in_decltype
|
201711L
|
(C++20)
(DR11) |
Génération de définitions de fonctions et de variables lorsque nécessaire pour l'évaluation constante |
__cpp_constexpr_dynamic_alloc
|
201907L
|
(C++20) | Opérations pour la durée de stockage dynamique dans les fonctions constexpr |
__cpp_constexpr
|
202306L
|
(C++26) | constexpr cast depuis void * : vers l'effacement de type constexpr |
202406L
|
(C++26) | constexpr placement new et new [ ] | |
__cpp_constexpr_exceptions
|
202411L
|
(C++26) | constexpr exceptions: [1] , [2] |
Exemple
|
Cette section est incomplète
Raison : aucun exemple |
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| CWG 94 | C++98 |
les expressions constantes arithmétiques ne pouvaient pas
impliquer de variables et de membres de données statiques |
elles le peuvent |
| CWG 366 | C++98 |
les expressions impliquant des littéraux de chaîne
pourraient être des expressions constantes entières |
elles ne le sont pas |
| CWG 457 | C++98 |
les expressions impliquant des variables volatiles
pouvaient être des expressions constantes intégrales |
elles ne le sont pas |
| CWG 1293 | C++11 |
il n'était pas clair si les littéraux de chaîne
sont utilisables dans les expressions constantes |
ils sont utilisables |
| CWG 1311 | C++11 | Les lvalues volatiles pouvaient être utilisées dans des expressions constantes | interdit |
| CWG 1312 | C++11 |
reinterpret_cast
est interdit dans les expressions constantes,
mais un transtypage vers et depuis void * pourrait produire le même effet |
conversions interdites
du type cv void * vers un type pointeur-vers-objet |
| CWG 1313 | C++11 |
le comportement indéfini était autorisé ;
toute soustraction de pointeurs était interdite |
Comportement indéfini interdit ; soustraction
de pointeurs sur le même tableau autorisée |
| CWG 1405 | C++11 |
pour les objets utilisables dans des expressions constantes,
leurs sous-objets mutables étaient également utilisables |
ils ne sont pas utilisables |
| CWG 1454 | C++11 |
le passage de constantes via des références dans des fonctions constexpr n'était pas autorisé
autorisé |
autorisé |
| CWG 1455 | C++11 | les expressions constantes converties ne pouvaient être que des prvalues | peuvent être des lvalues |
| CWG 1456 | C++11 |
une expression constante d'adresse ne pouvait pas
désigner l'adresse juste après la fin d'un tableau |
autorisé |
| CWG 1535 | C++11 |
une
typeid
expression dont l'opérande est d'un
type de classe polymorphe n'était pas une expression constante de base même si aucune vérification à l'exécution n'est impliquée |
la contrainte sur l'opérande
est limitée aux glvalues de types de classes polymorphes |
| CWG 1581 | C++11 |
les fonctions nécessaires pour l'évaluation constante n'étaient
pas requises d'être définies ou instanciées |
requis |
| CWG 1613 | C++11 |
les expressions constantes de base pouvaient évaluer toute
référence utilisée par odr dans les expressions lambda |
certaines références ne
pouvaient pas être évaluées |
| CWG 1694 | C++11 |
lier la valeur d'un temporaire à une référence de durée de stockage
statique était une expression constante |
ce n'est pas une
expression constante |
| CWG 1872 | C++11 |
les expressions constantes principales pouvaient invoquer
constexpr
les instanciations de modèles de fonctions
qui ne satisfont pas aux exigences des fonctions constexpr |
ces instanciations
ne peuvent pas être invoquées |
| CWG 1952 | C++11 |
les comportements indéfinis de la bibliothèque standard
devaient être diagnostiqués |
non spécifié si
ils sont diagnostiqués |
| CWG 2022 | C++98 |
la détermination d'une expression constante pourrait
dépendre du fait que l'élision de copie soit effectuée |
supposer que l'élision de copie
est toujours effectuée |
| CWG 2126 | C++11 |
les temporaires à durée de vie prolongée par initialisation constante de types littéraux
qualifiés const n'étaient pas utilisables dans les expressions constantes |
utilisable |
| CWG 2129 | C++11 | les littéraux entiers n'étaient pas des expressions constantes | ils le sont |
| CWG 2167 | C++11 |
références non-membres locales à une évaluation
rendaient l'évaluation non-constexpr |
références non-membres
autorisées |
| CWG 2278 | C++98 | la résolution de CWG issue 2022 n'était pas implémentable |
supposer que l'élision de copie
n'est jamais effectuée |
| CWG 2299 | C++14 |
il n'était pas clair si les macros dans
<cstdarg>
pouvaient être utilisées lors de l'évaluation constante |
va_arg
interdit,
va_start
non spécifié
|
| CWG 2400 | C++11 |
l'appel d'une fonction virtuelle constexpr sur un objet non utilisable
dans des expressions constantes et dont la durée de vie a commencé en dehors de l'expression contenant l'appel pourrait être une expression constante |
ce n'est pas une
expression constante |
| CWG 2490 | C++20 |
Les appels de (pseudo) destructeurs manquaient
de restrictions lors de l'évaluation constante |
restriction ajoutée |
| CWG 2552 | C++23 |
lors de l'évaluation d'une expression constante de base, le flux de contrôle
ne pouvait pas passer par une déclaration d'une variable non-bloc |
il peut |
| CWG 2558 | C++11 | une valeur indéterminée pourrait être une expression constante | pas une expression constante |
| CWG 2647 | C++20 | les variables de types qualifiés volatile pourraient être potentiellement constantes | elles ne le sont pas |
| CWG 2763 | C++11 |
la violation de
[[
noreturn
]]
n'était pas requise
d'être détectée durant l'évaluation constante |
requise |
| CWG 2851 | C++11 |
les expressions constantes converties n'autorisaient
pas les conversions de nombres à virgule flottante |
autoriser les conversions non-rétrécissantes
de nombres à virgule flottante |
| CWG 2907 | C++11 |
les expressions constantes de base ne pouvaient pas appliquer
les conversions lvalue-vers-rvalue aux std::nullptr_t glvalues |
peut appliquer de telles
conversions |
| CWG 2909 | C++20 |
une variable sans initialiseur ne pouvait être
initialisée de manière constante que si son initialisation par défaut entraîne l'exécution d'une certaine initialisation |
ne peut être initialisée de manière constante
que si son type est const-default-initializable |
| CWG 2924 |
C++11
C++23 |
il n'était pas spécifié si une expression violant
les contraintes de
[[
noreturn
]]
(C++11) ou
[[
assume
]]
(C++23) est une expression constante de base
|
c'est
défini par l'implémentation |
| P2280R4 | C++11 |
évaluer une expression contenant une expression d'identifiant
ou * this qui fait référence à un objet ou une référence dont la durée de vie a commencé en dehors de cette évaluation n'est pas une expression constante |
cela peut être une
expression constante |
Voir aussi
constexpr
spécificateur
(C++11)
|
spécifie que la valeur d'une variable ou fonction peut être calculée à la compilation |
|
(C++11)
(obsolète en C++17)
(supprimé en C++20)
|
vérifie si un type est un type littéral
(modèle de classe) |
|
Documentation C
pour
Expressions constantes
|
|