16

考虑以下代码:

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

如果我删除HERE代码编译良好的行,但如果我定义一个空的析构函数,它会导致编译错误,说它Test是非文字的。

为什么空析构函数和根本没有析构函数之间有什么区别?

编辑:另一个相关问题:如果空和文字析构函数不同,如何定义受保护的文字析构函数?

4

2 回答 2

20

来自 n3376 的报价

7.1.5/9

对象声明中使用的 constexpr 说明符将对象声明为 const。这样的对象应具有文字类型并应被初始化。如果它由构造函数调用初始化,则该调用应为常量表达式

3.9/10

如果满足以下条件,则类型是文字类型:

它有一个微不足道的析构函数......

12.4/5

如果析构函数不是用户提供的并且如果:

— 析构函数不是虚拟的,

— 其类的所有直接基类都有微不足道的析构函数,并且

— 对于其类的所有属于类类型(或其数组)的非静态数据成员,每个这样的类都有一个微不足道的析构函数。

否则,析构函数是不平凡的。

clang 诊断确实提供了更多信息:

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

'C' is not literal because it has a user-provided destructor
于 2013-01-10T10:39:36.067 回答
0

没有析构函数会导致编译器添加一个微不足道的析构函数,这在规范中定义不正确,但基本上什么都不做。

如果你指定一个析构函数,它不会添加平凡的析构函数。你的析构函数很重要。

在您的情况下,Test::~Test() { }看起来非常琐碎,但这是对您所见内容的人类解释。更进一步,关于:

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

我们可以看到优化器可以优化出 a,所以它显然什么都不做。怎么样:

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

我们可以看到它i永远不会是奇怪的,所以析构函数什么都不做。

规范必须定义什么可以是 constexpr,什么不能。他们没有深入定义“什么都不做”的兔子洞,而是简单地声明,唯一对 constexpr 足够好的无所事事析构函数是编译器提供的琐碎析构函数。

于 2013-09-06T22:28:42.123 回答