c++ c++11 destructor constexpr user-defined-literals

c++ - Destructor vacío vs destructor literal



c++11 constexpr (2)

Considere el siguiente código:

#include <iostream> class Test { public: constexpr Test(const int x) : _x(x) {} constexpr int get() const {return _x;} ~Test() {} // HERE protected: const int _x; }; int main() { static constexpr Test test(5); return 0; }

Si elimino la línea HERE el código se compila bien, pero si defino un destructor vacío, se produce un error de compilación que Test que la Test no es literal.

¿Por qué y cuál es la diferencia entre un destructor vacío y ningún destructor en absoluto?

EDITAR: Otra pregunta relacionada: si los destructores vacíos y literales son diferentes, ¿cómo definir un destructor literal protegido?


Citas de n3376

7.1.5 / 9

Un especificador constexpr utilizado en una declaración de objeto declara que el objeto es const. Dicho objeto tendrá un tipo literal y se inicializará. Si se inicializa mediante una llamada de constructor, esa llamada será una expresión constante

3.9 / 10

Un tipo es un tipo literal si:

tiene un destructor trivial ...

12.4 / 5

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

- El destructor no es virtual,

- todas las clases básicas directas de su clase tienen destructores triviales, y

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

De lo contrario, el destructor no es trivial.

clang diagnóstico es realmente más informativo:

error: constexpr variable cannot have non-literal type ''const C'' ''C'' is not literal because it has a user-provided destructor


Ningún destructor hace que el compilador agregue un destructor trivial, que está mal definido en la especificación, pero básicamente no hace nada.

Si especifica un destructor, no agrega el destructor trivial. Tu destructor no es trivial.

En su caso, Test::~Test() { } parece bastante trivial, pero esa es una interpretación humana de lo que ve. Para ir más lejos, ¿qué pasa con:

Test::~Test() { int a = 5; }

Podemos ver que un optimizador puede optimizar un, por lo que obviamente no está haciendo nada. Qué tal si:

Test::~Test() { for (int i = 0; i < 1000; i += 2) { if ((i % 2) == 1) doSomeSideEffect(); // like throwing or setting a global } }

Podemos ver que nunca puedo ser extraño, por lo que el destructor no hace nada.

La especificación tiene que definir qué se permite que sea un constexpr y qué no puede. En lugar de ir por este agujero de conejo de la definición de "no hacer nada", simplemente declaran que el único destructor de "no hacer nada" que es lo suficientemente bueno para constexpr es el destructor trivial proporcionado por el compilador.