我有类似以下的内容
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() { };
};
我想为派生类实现一些constexpr
null构造函数,但编译器对我所做的两个选项和类似测试抱怨很多。
当然代码更复杂,我有一个不透明的处理程序,析构函数应该以更复杂的方式运行。资源自由总是相同的(不需要多个析构函数,只需要Base
个)。
我不知道如何实现这一点,也许我正走错路?有任何想法吗?我希望能够做到这样的事情:
Derived a(nullptr);
Derived b(handler1);
Base c (nullptr);
Base d (handler2);
并且,在清理方面,handler1
和handler2
都以某种方式进行管理。
编辑:
Clang(3.4版)抱怨:
error: constexpr constructor never produces a constant expression [-Winvalid-constexpr]
gcc(版本4.8 [编辑:多个版本,尚未全部检查])在使用时没有抱怨
constexpr Derived(std::nullptr_t) : Base(nullptr) { };
事实上,gcc
似乎做了我想要实现的目标,但我不明白constexpr
足以知道哪个编译器正在做正确以及如何修改问题。
答案 0 :(得分:5)
常量表达式的类型必须是文字类型。事实上,“文字型”分类的整个目的是“成为一个可以不断表达的东西”。见[expr.const]:
条件表达式
e
是一个核心常量表达式,除非根据抽象机器(1.9)的规则评估e
将评估其中一个以下表达式:...
- 调用一个文字类的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
函数,包括构造函数:这些函数(包括构造函数)可以在静态初始化阶段调用,以使用静态存储持续时间对变量进行常量初始化。如果变量是对象,它们仍然保留其对象标识并且可能需要动态销毁,但它们的初始化在任何动态初始化之前发生,并且不需要排序。