38 votes

Pourquoi un destructeur ne peut-il pas être marqué constexpr ?

En C++, vous pouvez déclarer beaucoup de choses comme constexpr : variables, fonctions (y compris les fonctions membres et les opérateurs), constructeurs, et depuis C++1z, également if déclarations y expressions lambda . Cependant, déclarer un destructeur constexpr entraîne une erreur :

struct X {
    constexpr ~X() = default; // error: a destructor cannot be 'constexpr'
};

Mes questions :

  1. Pourquoi un destructeur ne peut-il pas être marqué constexpr ?
  2. Si je ne fournis pas de destructeur, est-ce que le destructeur implicitement généré est constexpr ?
  3. Si je déclare un destructeur par défaut ( ~X() = default; ), est-il automatiquement constexpr ?

0 votes

Pour (1), veuillez préciser si vous demandez où dans la norme il est dit qu'un destructeur ne peut pas être constexpr ; ou si vous demandez la justification de cette règle.

1 votes

@M.M Je suis principalement intéressé par l'endroit dans la norme où il est dit qu'un destructeur ne peut pas être constexpr, mais une justification de cette règle serait également agréable à connaître.

0 votes

Y a-t-il une raison pour laquelle constexpr serait utile sur un destructeur ? Je n'arrive pas à trouver un exemple convaincant où cela serait utile à un programme.

18voto

Hemant Gangwar Points 1770

Conformément à la projet.types.de.base#10 éventuellement un type de classe qualifié cv qui possède toutes les propriétés suivantes :

Un type de classe éventuellement qualifié de 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, soit d'un type d'agrégat, soit il a au moins un constructeur constexpr ou un modèle de constructeur (éventuellement). 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 l'un de ses membres de données non statiques non statiques est de type littéral non volatil.

(10.5.4) - s'il n'est pas une union, tous ses membres de données non statiques et ses classes de base sont de types littéraux non statiques.

Question 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 de la norme projet

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 triviaux, et

(5.6) - pour tous les membres de données non statiques de sa classe qui sont qui sont de type classe (ou tableau), chacune de ces classes a un destructeur destructeur trivial.

Sinon, le destructeur est non trivial.

Question 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.

Question 3 : Si je déclare un destructeur par défaut (~X() = default ;), est-il automatiquement constexpr ?

En effet, ce destructeur est déclaré par l'utilisateur et généré implicitement, il est donc qualifié pour constexpr.


Je ne suis pas en mesure de trouver une référence directe que seulement triviale destructors sont qualifiés pour constexpr mais si le destructeur n'est pas trivial alors il est certain que le type de classe n'est pas cv-qualified. Donc c'est un peu implicite comme vous ne pouvez pas définir une destructor para cv-qualified classe.


Mise à jour de C++20

Depuis C++20, les destructeurs définis par l'utilisateur peuvent également être constexpr sous certaines conditions.

dcl.constexpr/3 :

La définition d'une fonction constexpr doit satisfaire aux exigences suivantes 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 ;
  • il ne doit pas être une coroutine ([dcl.fct.def.coroutine]) ;
  • si la fonction est un constructeur ou un destructeur, sa classe ne doit pas avoir de classes de base virtuelles ;
  • son corps de fonction ne doit pas contenir ([stmt.pre])
    • une instruction goto,
    • une étiquette d'identification ([stmt.label]),
    • définition d'une variable de type non littéral ou de durée de stockage statique ou filaire. de stockage.

4 votes

Pouvez-vous ajouter une référence à cette affirmation ? Parce que seuls les destructeurs triviaux sont qualifiés pour constexpr.

0 votes

Si vous pouvez ajouter la macro de test de fonctionnalité qui vérifie la présence de cette fonctionnalité, ce serait comme une sauce. Je pense que c'est __cpp_constexpr_dynamic_alloc (P0784R7), mais je ne suis pas sûr à 100%.

7voto

saarraz1 Points 971

Si vous cherchez le raisonnement derrière la restriction, jetez un coup d'œil sur le site suivant cet article qui stipule clairement que la restriction est artificielle - il n'y a aucune propriété intrinsèque des destructeurs qui les empêche de fonctionner dans des contextes constexpr, et en effet les implémenteurs de compilateurs s'accordent à dire que leur prise en charge dans les contextes constexpr sera triviale à implémenter .

Je suppose que le comité de normalisation du C++ a initialement placé cette restriction dans le C++11 parce qu'il ne voulait pas s'occuper des destructeurs à ce moment-là et qu'il était plus facile de les exclure complètement.

4voto

R Sahu Points 24027

Pourquoi un destructeur ne peut pas être marqué comme constexpr ?

La norme C++11 est spécifique quant à l'utilisation de la fonction constexpr pour les consructeurs et les fonctions membres non statiques. Il ne dit rien de spécifique sur les destructeurs. On peut supposer que les destructeurs doivent être traités comme des fonctions membres non statiques.

constexpr ne peut être utilisé que pour const fonctions membres. Puisqu'un destructeur ne peut pas être const il ne peut être qualifié de fonction membre constexpr fonction membre.

Si je ne fournis pas de destructeur, est-ce que le destructeur implicitement généré est constexpr .

Puisque l'utilisation de

constexpr ~X() = default;

est une erreur, il me semble logique que le destructeur généré par le compilateur ne soit pas un constexpr fonction. Je ne trouve rien dans la norme pour justifier mon affirmation. Je devine.

Si je déclare un destructeur par défaut ( ~X() = default; ), est-il automatiquement constexpr

Je ne pense pas. Encore une fois, je ne trouve rien dans la norme qui justifie mon affirmation. Je devine.


Pour info, g++ compile et construit le programme suivant sans problème.

struct X {
   constexpr X(int i) : i_(i) {}
   ~X() = default;
   int i_;
};

int main()
{
   const X x(10);
}

5 votes

" constexpr ne peut être utilisé que pour const fonctions des membres". Ce n'est plus vrai depuis C++14.

3voto

Passer By Points 9171

Un destructeur ne peut pas être constexpr parce que constexpr Les fonctions ne peuvent pas avoir d'effets secondaires et les destructeurs, par définition, ne sont utiles que grâce aux effets secondaires. En bref, il serait inutile d'avoir un destructeur qui est constexpr .

Un objet ne peut pas être constexpr si son destructeur est non trivial. Un destructeur par défaut, s'il est trivial, sera considéré comme étant constexpr

En direct

Desde [class.dtor]

Chaque spécificateur de la séquence de spécificateurs d'une déclaration de destructeur (s'il y en a une) doit être friend , inline o virtual .

Il en manque, constexpr . Vous pouvez donc le prendre comme suit : parce que la norme le dit TM

7 votes

"Par définition, les destructeurs n'ont que des effets secondaires" n'est pas vrai. Il est facile d'écrire un destructeur qui n'a pas d'effet secondaire.

0 votes

@M.M Vous pouvez développer ? Les destructeurs n'ont pas d'arguments et ne renvoient rien, que faites-vous à l'intérieur de leur corps ?

3 votes

Tout ce que vous voulez. Le corps peut être vide, ou exécuter des instructions sans effets secondaires.

2voto

Rxmsc Points 927

Référence disons :

Constexpr destructeurs

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 non-triviaux sont un composant important du C++ moderne, en partie à cause de l'usage répandu de l'idiome RAII, qui est également applicable dans les évaluations constexpr. Les destructeurs non-triviaux pourraient être supportés dans des expressions constantes, comme suit :

  • Permettre aux destructeurs d'être marqués comme constexpr
  • Rendre les destructeurs par défaut constexpr s'ils n'invoquent que des destructeurs constexpr.
  • Pour les variables constexpr, il faut que l'évaluation du destructeur soit une expression constante (sauf que l'objet détruit peut être modifié dans son propre destructeur). modifié dans son propre destructeur

Cependant, aucun cas d'utilisation convaincant n'est connu pour une telle fonctionnalité, et et il y aurait un coût d'implémentation non trivial pour s'assurer que les destructrices sont exécutées au bon moment.

0 votes

Un cas d'utilisation ne serait-il pas l'évaluation en temps de compilation de mathématiques complexes ? Mais je suppose que l'implémentation correcte d'une telle fonctionnalité serait une douleur majeure pour les programmeurs de compilateurs et ne vaudrait probablement pas la peine.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X