constexpr
specifier
(since C++11)
-
-
constexpr- spécifie que la valeur d'une variable , structured binding (depuis C++26) ou d'une fonction peut apparaître dans des expressions constantes
-
Table des matières |
Explication
Le spécificateur constexpr déclare qu'il est possible d'évaluer la valeur des entités au moment de la compilation. Ces entités peuvent ensuite être utilisées là où seules les expressions constantes de compilation sont autorisées (à condition que des arguments de fonction appropriés soient fournis).
Un spécificateur constexpr utilisé dans une déclaration d'objet ou de fonction membre non statique (jusqu'en C++14) implique const .
Un spécificateur constexpr utilisé dans la première déclaration d'une fonction ou d'un membre de données statique (depuis C++17) implique inline . Si une déclaration d'une fonction ou d'un modèle de fonction possède un spécificateur constexpr , alors chaque déclaration doit contenir ce spécificateur.
constexpr variable
Une variable ou un modèle de variable (depuis C++14) peut être déclarée constexpr si toutes les conditions suivantes sont satisfaites :
- La déclaration est une définition .
- Elle est d'un literal type .
- Elle est initialisée (par la déclaration).
|
(jusqu'en C++26) |
|
(depuis C++26) |
|
Si une variable constexpr n'est pas locale à l'unité de traduction , elle ne doit pas être initialisée pour référencer une entité locale à l'unité de traduction utilisable dans des expressions constantes, ni avoir un sous-objet qui référence une telle entité. Une telle initialisation est interdite dans une unité d'interface de module (en dehors de son fragment de module privé , s'il existe) ou dans une partition de module, et est dépréciée dans tout autre contexte. |
(depuis C++20) |
constexpr fonction
Une fonction ou un modèle de fonction peut être déclaré constexpr .
Une fonction est constexpr-suitable si toutes les conditions suivantes sont satisfaites :
|
(jusqu'en C++20) |
|
(jusqu'en C++23) |
|
(depuis C++20) |
|
(jusqu'en C++14) | ||
|
(depuis C++14)
(jusqu'en C++23) |
Sauf pour les fonctions constexpr instanciées, les fonctions non-templatisées constexpr doivent être adaptées pour constexpr.
|
Pour une fonction constexpr non-constructrice qui n'est ni par défaut ni templatée, s'il n'existe aucune valeur d'argument telle qu'un appel de la fonction puisse être une sous-expression évaluée d'une expression constante de base , le programme est mal formé, aucun diagnostic requis. Pour une fonction templatée constexpr , si aucune spécialisation de la fonction/du modèle de classe ne rendrait la fonction templatée adaptée à constexpr lorsqu'elle est considérée comme une fonction non-templatée, le programme est mal formé, aucun diagnostic requis. |
(until C++23) |
Un appel d'une fonction constexpr dans un contexte donné produit le même résultat qu'un appel d'une fonction non- constexpr équivalente dans le même contexte à tous égards, avec les exceptions suivantes :
- Un appel d'une fonction constexpr peut apparaître dans une expression constante .
- L'élision de copie n'est pas effectuée dans une expression constante.
constexpr constructeur
En plus des exigences des fonctions constexpr , un constructeur doit également satisfaire à toutes les conditions suivantes pour être adapté à constexpr :
|
(jusqu'à C++23) |
- La classe n'a aucune virtual base class .
|
Pour un constructeur constexpr qui n'est ni par défaut ni template, s'il n'existe aucune valeur d'argument telle qu'un appel de la fonction pourrait être une sous-expression évaluée de l'expression complète d'initialisation d'un objet soumis à une expression constante , le programme est mal formé, aucun diagnostic requis. |
(jusqu'à C++23) |
constexpr destructeur
|
Les destructeurs ne peuvent pas être constexpr , mais un destructeur trivial peut être appelé implicitement dans les expressions constantes. |
(jusqu'à C++20) | ||
|
En plus des exigences des fonctions constexpr , un destructeur doit également satisfaire toutes les conditions suivantes pour être éligible comme constexpr :
|
(depuis C++20) |
Notes
|
Étant donné que l'opérateur
constexpr int f(); constexpr bool b1 = noexcept(f()); // false, undefined constexpr function constexpr int f() { return 0; } constexpr bool b2 = noexcept(f()); // true, f() is a constant expression |
(jusqu'en C++17) |
|
Il est possible d'écrire une fonction constexpr dont l'invocation ne peut jamais satisfaire les exigences d'une expression constante de base : void f(int& i) // not a constexpr function { i = 0; } constexpr void g(int& i) // well-formed since C++23 { f(i); // unconditionally calls f, cannot be a constant expression } |
(depuis C++23) |
Les constructeurs constexpr sont autorisés pour les classes qui ne sont pas des types littéraux. Par exemple, le constructeur par défaut de std::shared_ptr est constexpr, permettant une initialisation constante .
Les variables de référence peuvent être déclarées constexpr (leurs initialiseurs doivent être des expressions constantes de référence ) :
static constexpr int const& x = 42; // référence constexpr vers un objet const int // (l'objet a une durée de stockage statique // en raison de l'extension de durée de vie par une référence statique)
|
Bien que try blocks et l'assemblage en ligne soient autorisés dans les fonctions constexpr, lever des exceptions qui ne sont pas capturées (depuis C++26) ou exécuter l'assemblage reste interdit dans une expression constante. Si une variable a une destruction constante, il n'est pas nécessaire de générer du code machine pour appeler son destructeur, même si son destructeur n'est pas trivial. Une fonction constexpr non-lambda, non-spéciale-membre et non-templatée ne peut pas devenir implicitement une fonction immédiate. Les utilisateurs doivent explicitement la marquer consteval pour rendre une telle définition de fonction valide. |
(depuis C++20) |
| Macro de test de fonctionnalité | Valeur | Std | Fonctionnalité |
|---|---|---|---|
__cpp_constexpr
|
200704L
|
(C++11) | constexpr |
201304L
|
(C++14) | Assouplissement de constexpr , méthodes constexpr non- const | |
201603L
|
(C++17) | Lambda constexpr | |
201907L
|
(C++20) | Initialisation par défaut triviale et déclaration asm dans les fonctions constexpr | |
202002L
|
(C++20) | Modification du membre actif d'une union lors de l'évaluation constante | |
202110L
|
(C++23) | Variables non- littérales , étiquettes et goto dans les fonctions constexpr | |
202207L
|
(C++23) | Assouplissement de certaines restrictions constexpr | |
202211L
|
(C++23) | Autorisation des variables static constexpr dans les fonctions constexpr | |
202306L
|
(C++26) | Conversion constexpr de void * : vers l'effacement de type constexpr | |
__cpp_constexpr_in_decltype
|
201711L
|
(C++11)
(DR) |
Génération de définitions de fonctions et de variables lorsque nécessaires pour l'évaluation constante |
__cpp_constexpr_dynamic_alloc
|
201907L
|
(C++20) | Opérations pour la durée de stockage dynamique dans les fonctions constexpr |
Mots-clés
Exemple
Définit les fonctions constexpr C++11/14 qui calculent les factorielles ; définit un type littéral qui étend les littéraux de chaîne :
#include <iostream> #include <stdexcept> // Les fonctions constexpr de C++11 utilisent la récursion plutôt que l'itération constexpr int factorial(int n) { return n <= 1 ? 1 : (n * factorial(n - 1)); } // Les fonctions constexpr de C++14 peuvent utiliser des variables locales et des boucles #if __cplusplus >= 201402L constexpr int factorial_cxx14(int n) { int res = 1; while (n > 1) res *= n--; return res; } #endif // C++14 // Une classe littérale class conststr { const char* p; std::size_t sz; public: template<std::size_t N> constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {} // Les fonctions constexpr signalent les erreurs en lançant des exceptions // En C++11, elles doivent le faire depuis l'opérateur conditionnel ?: constexpr char operator[](std::size_t n) const { return n < sz ? p[n] : throw std::out_of_range(""); } constexpr std::size_t size() const { return sz; } }; // Les fonctions constexpr de C++11 devaient tout mettre dans une seule instruction return // (C++14 n'a pas cette exigence) constexpr std::size_t countlower(conststr s, std::size_t n = 0, std::size_t c = 0) { return n == s.size() ? c : 'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) : countlower(s, n + 1, c); } // Une fonction de sortie qui nécessite une constante à la compilation, pour les tests template<int n> struct constN { constN() { std::cout << n << '\n'; } }; int main() { std::cout << "4! = "; constN<factorial(4)> out1; // calculé à la compilation volatile int k = 8; // empêche l'optimisation en utilisant volatile std::cout << k << "! = " << factorial(k) << '\n'; // calculé à l'exécution std::cout << "Le nombre de lettres minuscules dans \"Hello, world!\" est "; constN<countlower("Hello, world!")> out2; // implicitement converti en conststr constexpr int a[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; constexpr int length_a = sizeof a / sizeof(int); // std::size(a) en C++17, // std::ssize(a) en C++20 std::cout << "Le tableau de longueur " << length_a << " a pour éléments : "; for (int i = 0; i < length_a; ++i) std::cout << a[i] << ' '; std::cout << '\n'; }
Sortie :
4! = 24 8! = 40320 Le nombre de lettres minuscules dans "Hello, world!" est 9 Un tableau de longueur 12 a pour éléments : 0 1 2 3 4 5 6 7 8 0 0 0
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 1358 | C++11 |
les fonctions
constexpr
template devaient aussi
avoir au moins une valeur d'argument valide |
pas nécessaire |
| CWG 1359 | C++11 |
les constructeurs
constexpr
d'union
devaient initialiser tous les membres de données |
initialise exactement un membre
de données pour les unions non vides |
| CWG 1366 | C++11 |
les classes avec des constructeurs
constexpr
dont les corps
sont = default ou = delete pouvaient avoir des classes de base virtuelles |
ces classes ne peuvent
pas avoir de classes de base virtuelles |
| CWG 1595 | C++11 |
les constructeurs délégués
constexpr
exigeaient
que tous les constructeurs impliqués soient constexpr |
exige seulement que le constructeur
cible soit constexpr |
| CWG 1712 | C++14 |
un template de variable
constexpr
devait avoir
toutes ses déclarations contenant le spécificateur constexpr [1] |
n'est plus exigé |
| CWG 1911 | C++11 | les constructeurs constexpr pour les types non littéraux n'étaient pas autorisés | autorisés dans l'initialisation constante |
| CWG 2004 | C++11 |
la copie/déplacement d'une union avec un membre mutable
était autorisée dans une expression constante |
les variantes mutables disqualifient
la copie/déplacement implicite |
| CWG 2022 | C++98 |
le fait que des fonctions
constexpr
et non-
constexpr
équivalentes produisent un résultat égal pouvait dépendre de l'élimination de copie |
suppose que l'élimination de copie est toujours
effectuée dans les expressions constantes |
| CWG 2163 | C++14 |
les étiquettes étaient autorisées dans les fonctions
constexpr
même si les instructions goto sont interdites |
les étiquettes sont également interdites |
| CWG 2268 | C++11 |
la copie/déplacement d'une union avec un membre mutable était
interdite par la résolution de CWG issue 2004 |
autorisée si l'objet est créé
dans l'expression constante |
| CWG 2278 | C++98 | la résolution de CWG issue 2022 n'était pas implémentable |
suppose que l'élimination de copie n'est jamais
effectuée dans les expressions constantes |
| CWG 2531 | C++11 |
une variable non inline devenait inline
si elle est redéclarée avec constexpr |
la variable ne
devient pas inline |
- ↑ C'est redondant car il ne peut y avoir plus d'une déclaration d'un modèle de variable avec le spécificateur constexpr .
Voir aussi
| expression constante | définit une expression qui peut être évaluée à la compilation |
consteval
specifier
(C++20)
|
spécifie qu'une fonction est une fonction immédiate , c'est-à-dire que chaque appel à la fonction doit être dans une évaluation constante |
constinit
specifier
(C++20)
|
affirme qu'une variable a une initialisation statique, c'est-à-dire initialisation à zéro et initialisation constante |
|
Documentation C
pour
constexpr
|
|