En C++, vous pouvez déclarer beaucoup de choses comme constexpr
: variables, fonctions (y compris les fonctions membres et opérateurs), constructeurs, et depuis C++ 1z, aussi if
instructions et expressions lambda . Cependant, déclarer un destructeurconstexpr
entraîne une erreur:
struct X {
constexpr ~X() = default; // error: a destructor cannot be 'constexpr'
};
Mes questions:
constexpr
?constexpr
?~X() = default;
), est-ce automatiquement constexpr
?Selon le type de classe draft basic.types # 1 éventuellement qualifié cv qui possède toutes les propriétés suivantes:
Un type de classe éventuellement qualifié par cv qui possède toutes les propriétés suivantes:
(10.5.1) - il a un destructeur trivial,
(10.5.2) - il s'agit soit d'un type de fermeture, d'un type d'agrégat, soit d'au moins un constructeur constexpr ou un modèle de constructeur (éventuellement hérité d'une classe de base) qui n'est pas un constructeur de copie ou de déplacement,
(10.5.3) - s'il s'agit d'une union, au moins un de ses membres de données non statiques est de type littéral non volatile
(10.5.4) - s'il ne s'agit pas d'une union, tous ses membres de données non statiques et ses classes de base sont de types littéraux non volatils.
Ques 1: Pourquoi un destructeur ne peut pas être marqué comme constexpr?
Parce que seuls les destructeurs triviaux sont qualifiés pour constexpr Voici la section pertinente du draft
Un destructeur est trivial s'il n'est pas fourni par l'utilisateur et si:
(5.4) - le destructeur n'est pas virtuel,
(5.5) - toutes les classes de base directes de sa classe ont des destructeurs triviaux, et
(5.6) - pour tous les membres de données non statiques de sa classe qui sont de type classe (ou tableau de ceux-ci), chacune de ces classes a un destructeur trivial.
Sinon, le destructeur n'est pas trivial.
Ques 2: Si je ne fournis pas de destructeur, le destructeur généré implicitement est-il constexpr?
Oui, car le destructeur généré implicitement est de type trivial, il est donc qualifié pour constexpr
Ques 3: Si je déclare un destructeur par défaut (~ X () = default;), est-ce automatiquement constexpr?
En effet, ce destructeur est déclaré par l'utilisateur et généré implicitement et il est donc qualifié pour constexpr.
Je ne suis pas en mesure de trouver une référence directe que seuls _ triviaux destructors
sont qualifiés pour constexpr
mais si le destructeur n'est pas trivial, il est certain que le type de classe n'est pas cv-qualified.
Donc, c'est un peu implicite car vous ne pouvez pas définir un destructor
pour cv-qualified
classe.
Depuis C++ 20, les destructeurs définis par l'utilisateur peuvent également être constexpr sous certaines conditions.
La définition d'une fonction constexpr doit satisfaire aux exigences suivantes:
- son type de retour (le cas échéant) doit être un type littéral;
- chacun de ses types de paramètres doit être un type littéral;
- ce ne doit pas être une coroutine ([dcl.fct.def.coroutine]);
- si la fonction est un constructeur ou un destructeur, sa classe ne doit avoir aucune classe de base virtuelle;
- son corps de fonction ne doit pas contenir ([stmt.pre])
- une déclaration goto,
- un identifiant ([stmt.label]),
- une définition d'une variable de type non littéral ou de durée de stockage statique ou de thread.
Si ce que vous recherchez est le raisonnement derrière la restriction, jetez un œil à ce document qui indique clairement que la restriction est artificielle - il n'y a aucune propriété intrinsèque des destructeurs qui les empêche de travailler dans des contextes constexpr, et en effet les implémenteurs du compilateur conviennent que les supporter dans des contextes constexpr sera trivial à implémenter .
Je suppose que le comité des normes C++ a initialement placé la restriction dans C++ 11 parce qu'il ne voulait pas traiter avec les destructeurs à ce moment-là et il était plus facile de les exclure complètement.
Pourquoi un destructeur ne peut pas être marqué comme constexpr?
La norme C++ 11 est spécifique à l'utilisation de constexpr
pour les constructeurs et les fonctions membres non statiques. Il ne dit rien de spécifique sur le destructeur. On peut supposer que les destructeurs doivent être traités comme des fonctions membres non statiques.
constexpr
ne peut être utilisé que pour les fonctions membres const
. Puisqu'un destructeur ne peut pas être une fonction membre const
, il ne peut pas être qualifié de fonction membre constexpr
.
Si je ne fournis pas de destructeur, c'est le destructeur généré implicitement
constexpr
.
Depuis l'utilisation de
constexpr ~X() = default;
est une erreur, il est logique pour moi que le destructeur généré par le compilateur ne soit pas une fonction constexpr
. Je ne trouve rien dans la norme pour justifier ma déclaration. Je devine.
Si je déclare un destructeur par défaut (
~X() = default;
), est-ce automatiquementconstexpr
Je crois que non. Encore une fois, je ne trouve rien dans la norme pour justifier ma déclaration. Je devine.
FWIW, g ++ compile et construit très bien le programme suivant.
struct X {
constexpr X(int i) : i_(i) {}
~X() = default;
int i_;
};
int main()
{
const X x(10);
}
Un destructeur ne peut pas être constexpr
car les fonctions constexpr
ne peuvent pas avoir d'effets secondaires et les destructeurs par définition ne sont utiles que par le biais d'effets secondaires. Bref, il serait inutile d'avoir un destructeur qui est constexpr
.
Un objet ne peut pas être constexpr
si son destructeur n'est pas trivial. Une valeur par défaut, si triviale, sera considérée comme constexpr
De [class.dtor]
Chaque spécificateur décl de la spécification décl-seq d'une déclaration de destructeur (le cas échéant) doit être
friend
,inline
ouvirtual
.
Manquant, constexpr
. Donc, vous pouvez simplement le prendre comme suit: parce que la norme le ditTM
Référence disons:
destructeurs constexpr
Dans la plupart des cas, pour créer un objet de type T dans une expression constante, la destruction de T doit être triviale. Cependant, les destructeurs non triviaux sont un composant important du C++ moderne, en partie en raison de l'utilisation généralisée de l'idiome RAII, qui est également applicable dans les évaluations constexpr. Les destructeurs non triviaux peuvent être pris en charge dans les expressions constantes, comme suit:
- Autoriser les destructeurs à être marqués comme constexpr
- Rendre les destructeurs par défaut constexpr s'ils invoquent uniquement les destructeurs constexpr
- Pour les variables constexpr, exiger que l'évaluation du destructeur soit une expression constante (sauf que l'objet détruit peut être modifié dans son propre destructeur
Cependant, aucun cas d'utilisation convaincant n'est connu pour une telle fonctionnalité, et il y aurait un coût d'implémentation non trivial garantissant que les destructeurs sont exécutés au bon moment.
Depuis C++ 20, un constructeur peut être marqué constexpr
; Je ne sais pas si cela dit quelque part spécifiquement "un destructeur peut être constexpr
", mais le projet de norme inclut le texte suivant dans la section 9.2.5 paragraphe 5:
La définition d'un destructeur
constexpr
dont le corps de fonction n'est pas= delete
doit en outre satisfaire à l'exigence suivante:
- pour chaque sous-objet du type de classe ou de son tableau (éventuellement multidimensionnel), ce type de classe doit avoir un destructeur constexpr.
Cela a également une fonction utile car C++ 20 permet également new
et delete
dans les contextes constexpr
, ce qui permet des choses comme vector
et string
pour travailler à la compilation sans hacks (bien que je pense que C++ 20 n'inclut pas réellement les modifications de la bibliothèque standard pour permettre cela, il est possible d'implémenter quelque chose avec la même API et le même comportement que vector
qui fonctionne complètement au moment de la compilation).