我有类似以下内容
class Base {
public:
explicit Base(int* i) noexcept { type = new int; *type = *i; };
constexpr Base(std::nullptr_t) : type(nullptr) { };
~Base() { cout << "Destroying!" << endl; delete type; };
protected:
int* type;
};
class Derived : public Base {
public:
explicit Derived(int* i) noexcept : Base(i) { };
//constexpr Derived(std::nullptr_t) : type(nullptr) { };
//constexpr Derived(std::nullptr_t) : Base(nullptr) { };
~Derived() { };
};
Run Code Online (Sandbox Code Playgroud)
我想constexpr为派生类实现一些null构造函数,但编译器对我所做的两个选项和类似测试抱怨很多.
当然代码更复杂,我有一个不透明的处理程序,析构函数应该以更复杂的方式运行.资源自由总是相同的(不需要多个析构函数,只需要Base一个).
我不知道如何实现这一点,也许我正走错路?有任何想法吗?我希望能够做到这样的事情:
Derived a(nullptr);
Derived b(handler1);
Base c (nullptr);
Base d (handler2);
Run Code Online (Sandbox Code Playgroud)
并且,在清理,都handler1和handler2都在某种方式进行管理.
编辑:
Clang(3.4版)抱怨:
error: constexpr constructor never produces a constant expression [-Winvalid-constexpr]
Run Code Online (Sandbox Code Playgroud)
而gcc(版本4.8 [编辑:多个版本,尚未全部检查])在使用时不会抱怨
constexpr Derived(std::nullptr_t) : Base(nullptr) { };
Run Code Online (Sandbox Code Playgroud)
事实上,gcc似乎做了我想要实现的目标,但我不明白constexpr知道哪个编译器做得正确以及如何修改问题.
常量表达式的类型必须是文字类型.事实上,"文字型"分类的整个目的是"成为一个可以不断表达的东西".见[expr.const]:
甲条件表达式
e是一个核心常量表达式除非的评价e,如下所述抽象机(1.9),将评估下面的表达式中的一个的规则:...
- 为constexpr函数调用constexpr构造函数以外的函数,constexpr函数,
...
因此,constexpr构造函数只允许您在文字类上生成常量表达式,否则,正如您的编译器告诉您的那样,它将"永远不会产生常量表达式".
文字类以这种方式受[basic.types]约束:
类型是文字类型,如果它是:
...
- 具有以下所有属性的类类型(第9节):
- 它有一个简单的析构函数,
- 它是聚合类型(8.5.1)或至少有一个
constexpr构造函数或构造函数模板,它不是复制或移动构造函数,并且- 它的所有非静态数据成员和基类都是非易失性文字类型.
但是,从C++ 14开始(特别是从N3652开始),constexpr构造函数有另一种不相关的用法:它们允许静态初始化(在[basic.start.init]意义上):
甲恒定初始化为一个对象
o是一个常量表达式,除了它也可以调用表达式constexpr用于构造o和它的子对象,即使这些对象是非文字类类型[的注意:这样的类可具有一个非平凡的析构函数- 结束说明 ].
所以回顾一下:从C++ 14开始,constexpr有两个用途:
C++ 11解释:"常量表达式"是一个与其值相同的表达式(即它的评估没有副作用); constexpr变量只是它们的值的占位符,并不打算用于它们的对象标识,并且通常期望常量表达式可以用它们的(编译时可知的)值自由替换.
C++ 14 constexpr函数,包括构造函数:这些函数(包括构造函数)可以在静态初始化阶段调用,以使用静态存储持续时间对变量进行常量初始化.如果变量是对象,它们仍然保留其对象标识并且可能需要动态销毁,但是它们的初始化在任何动态初始化之前发生并且不需要排序.