c++ language-lawyer constexpr

c++ - ¿Por qué no se puede marcar un destructor como constexpr?



language-lawyer (5)

¿Por qué un destructor no puede ser marcado como constexpr?

El estándar C ++ 11 es específico sobre el uso de constexpr para constexpr y funciones miembro no estáticas. No dice nada específico sobre el destructor. Se puede suponer que los destructores deben tratarse como funciones miembro no estáticas.

constexpr se puede utilizar para funciones miembro const . Dado que un destructor no puede ser una función miembro const , no puede ser calificado como una función miembro constexpr .

Si no proporciono un destructor, es el destructor generado implícitamente constexpr .

Desde el uso de

constexpr ~X() = default;

es un error, tiene sentido para mí que el destructor generado por el compilador no sea una función constexpr . No puedo encontrar nada en el estándar para justificar mi declaración. Estoy adivinando.

Si declaro un destructor predeterminado ( ~X() = default; ), es automáticamente constexpr

Yo creo que no. Una vez más, no puedo encontrar nada en el estándar para justificar mi declaración. Estoy adivinando.

FWIW, g ++ compila y construye el siguiente programa muy bien.

struct X { constexpr X(int i) : i_(i) {} ~X() = default; int i_; }; int main() { const X x(10); }

En C ++, puede declarar muchas cosas como constexpr : variables, funciones (incluidas las funciones miembro y operadores), constructores, y desde C ++ 1z, también if declaraciones y expresiones lambda . Sin embargo, declarar un constexpr destructor produce un error:

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

Mis preguntas:

  1. ¿Por qué no se puede marcar un destructor como constexpr ?
  2. Si no proporciono un destructor, ¿el destructor generado implícitamente es constexpr ?
  3. Si declaro un destructor predeterminado ( ~X() = default; ), ¿es automáticamente constexpr ?

Según el borrador de tipo de clase basic.types # 10 posiblemente cv-calificado que tiene todas las siguientes propiedades:

Un tipo de clase posiblemente cv calificado que tiene todas las siguientes propiedades:

(10.5.1) - tiene un destructor trivial,

(10.5.2): es un tipo de cierre, un tipo agregado o tiene al menos un constructor constexpr o una plantilla de constructor (posiblemente heredada de una clase base) que no es un constructor de copia o movimiento,

(10.5.3) - si es una unión, al menos uno de sus miembros de datos no estáticos es de tipo literal no volátil

(10.5.4) - si no es una unión, todos sus miembros de datos no estáticos y sus clases base son de tipos literales no volátiles.

Ques 1: ¿Por qué un destructor no puede ser marcado como constexpr?

Porque solo los destructores triviales están calificados para constexpr A continuación se encuentra la sección relevante del draft

Un destructor es trivial si no es proporcionado por el usuario y si:

(5.4) - El destructor no es virtual,

(5.5) - todas las clases base directas de su clase tienen destructores triviales, y

(5.6) - para todos los miembros de datos no estáticos de su clase que son de tipo de clase (o conjunto de los mismos), cada clase tiene un destructor trivial.

De lo contrario, el destructor no es trivial.

Pregunta 2: Si no proporciono un destructor, ¿el constexpr generado implícitamente es constexpr?

Sí, porque el destructor generado implícitamente es de tipo trivial, por lo que está calificado para constexpr

Pregunta 3: si declaro un destructor predeterminado (~ X () = predeterminado;), ¿es constexpr automáticamente?

De hecho, este destructor está declarado por el usuario y se genera implícitamente, por lo que está calificado para constexpr.

No puedo encontrar ninguna referencia directa de que solo los destructors triviales estén calificados para constexpr pero si el destructor no es trivial, es seguro que el tipo de clase no está cv-qualified. Por lo tanto, es algo implícito, ya que no se puede definir un destructor para cv-qualified clase cv-qualified CV.


Si lo que busca es razonar detrás de la restricción, eche un vistazo a este documento que indica claramente que la restricción es artificial : no hay una propiedad intrínseca de los destructores que les impida trabajar en contextos constexpr, y de hecho los implementadores del compilador aceptan que Apoyarlos en contextos constexpr será trivial de implementar .

Supongo que el comité de estándares de C ++ originalmente colocó la restricción en C ++ 11 porque no querían tratar con los destructores en ese momento y era más fácil simplemente descartarlos por completo.


Un destructor no puede ser constexpr porque constexpr funciones constexpr no pueden tener efectos secundarios y, por definición, los destructores solo son útiles a través de los efectos secundarios. En resumen, sería inútil tener un destructor que sea constexpr .

Un objeto no puede ser constexpr si su destructor no es trivial. Una por defecto, si es trivial, se considerará constexpr

Live

De [class.dtor]

Cada especificador decl del decl-specifier-seq de una declaración de destructor (si existe) debe ser friend , en inline o virtual .

Falta de ella, constexpr . Así que puedes simplemente tomarlo como: porque el estándar lo dice TM


Reference :

constexpr destructores

En la mayoría de los casos, para crear un objeto de tipo T en una expresión constante, la destrucción de T debe ser trivial. Sin embargo, los destructores no triviales son un componente importante del C ++ moderno, en parte debido al uso generalizado del lenguaje RAII, que también es aplicable en las evaluaciones constexpr. Los destructores no triviales podrían ser soportados en expresiones constantes, de la siguiente manera:

  • Permitir que los destructores sean marcados como constexpr
  • Hacer que los destructores predeterminados sean constexpr si solo invocan a constexpr destructores
  • Para las variables constexpr, se requiere que evaluar el destructor sea una expresión constante (excepto que el objeto que se destruye puede modificarse en su propio destructor).

Sin embargo, no se conocen casos de uso convincentes para tal característica, y habría un costo de implementación no trivial que garantice que los destructores se ejecuten en el momento adecuado.