Question

Consider the following code:

#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;
}

If I remove the line HERE the code compiles well, but if I define an empty destructor, it results to a compilation error saying that Test is non-literal.

Why and what is the difference between an empty destructor and no destructor at all ?

EDIT: Another related question : if empty and literal destructors are different how to define a protected literal destructor ?

Was it helpful?

Solution

Quotes from n3376

7.1.5/9

A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression

3.9/10

A type is a literal type if:

it has a trivial destructor...

12.4/5

A destructor is trivial if it is not user-provided and if:

— the destructor is not virtual,

— all of the direct base classes of its class have trivial destructors, and

— for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.

Otherwise, the destructor is non-trivial.

clang diagnostic is really more informative:

error: constexpr variable cannot have non-literal type 'const C'

'C' is not literal because it has a user-provided destructor

OTHER TIPS

No destructor causes the compiler to add a trivial destructor, which is ill defined in the spec, but basically does nothing.

If you specify a destructor, it does not add the trivial destructor. Your destructor is non-trivial.

In your case, Test::~Test() { } looks pretty darn trivial, but that is a human interpretation of what you see. To go further, what about:

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

We can see that an optimizer can optimize out a, so it is obviously doing nothing. How about:

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

We can see that i can never be odd, so that destructor does nothing.

The spec has to define what is allowed to be a constexpr and what cannot. Rather than going down this rabbit hole of defining "doing nothing," they simply declare that the only do-nothing destructor that is good enough for constexpr is the compiler provided trivial destructor.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top