派生类中用于空初始化构造函数的constexpr [英] constexpr for null-initialized constructor in a derived class

查看:55
本文介绍了派生类中用于空初始化构造函数的constexpr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有类似以下内容

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派生类的构造函数,但是编译器抱怨这两个选项和我所做的类似测试。

I would like to achieve some constexpr null constructor for the derived class, but the compiler complains a lot about the two options and similar tests I have done.

当然,代码更复杂,我有点不透明处理程序和析构函数的行为应更为复杂。资源释放总是相同的(不需要多个析构函数,只需要 Base 个)。

Of course the code is more complex, I have an opaque handler and the destructor should behave in a more complex way. The resource free-ing is always the same (no need for multiple destructors, only the Base one).

我不知道如何实现这一目标,也许我走错了路?有任何想法吗?我希望能够执行以下操作:

I don't know how to achieve this, maybe I am going through a wrong path? Any ideas? I expect to be able to do something like:

Derived a(nullptr);
Derived b(handler1);
Base c (nullptr);
Base d (handler2);

,并且在清理过程中, handler1 handler2 以某种方式进行管理。

and, in cleanup, both handler1 and handler2 are managed in the some way.

编辑:

Clang(版本3.4)抱怨:

Clang (version 3.4) complains:

error: constexpr constructor never produces a constant expression [-Winvalid-constexpr]

和gcc(版本4.8 [edit:多个版本,尚未全部检查])没有抱怨使用

And gcc (version 4.8 [edit: multiple versions, haven't checked all]) doesn't complain when using

constexpr Derived(std::nullptr_t) : Base(nullptr) { };

实际上, gcc 似乎在做什么我想实现,但是我对 constexpr 不够了解,无法知道哪个编译器运行正确以及如何解决该问题。

In fact, gcc seems to do what I wanted to achieve, but I do not understand the constexpr enough to know which compiler is doing right and how I can amend the problem.

推荐答案

常量表达式的类型必须为文字类型。实际上,文字类型分类单元的全部目的是成为可以成为常量表达的事物。参见[expr.const]:

The type of a constant expression must be a literal type. In fact, the entire purpose of the "literal type" taxon is to "be the thing that can be a constant expression". See [expr.const]:


A 条件表达式 e 是一个核心常量表达式,除非遵循抽象机(1.9)的规则对 e 的求值将对以下表达式之一求值:

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:

...

—调用文字类的constexpr构造函数以外的函数,一个constexpr函数,

— an invocation of a function other than a constexpr constructor for a literal class, a constexpr function,

...

因此, constexpr 构造函数只允许您在文字类上生成常量表达式,否则,正如编译器告诉您的那样,它将从不生成常量表达式。

Therefore, a constexpr constructor only allows you to produce constant expressions on literal classes, and otherwise, as your compiler is telling you, it would "never produce a constant expression".

文字类受到[basic.types]的限制:

A literal class is constrained by [basic.types] in this way:


A类型是文字类型,如果它是:

...

具有以下所有属性的类类型(第9条):

— a class type (Clause 9) that has all of the following properties:


  • 它具有琐碎的析构函数,

  • 它是聚合类型(8.5.1)或至少具有一个 constexpr 构造函数或非复制或移动构造函数模板,并且

  • 其所有非静态数据成员和基类是非易失性文字类型。

  • it has a trivial destructor,
  • it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and
  • all of its non-static data members and base classes are of non-volatile literal types.

但是,从C ++开始14(尤其是 N3652 ), constexpr 构造函数还有另一个不相关的用途:它们允许静态初始化(在[basic.start.init]的意义上):

However, as of C++14 (particularly, as of N3652), constexpr constructors have another, unrelated use: They permit static initialization (in the sense of [basic.start.init]):


对象 o 常量初始化程序是一个
的表达式常量表达式,除了它也可以为 o 及其子对象调用 constexpr 构造函数,即使这些对象不是文字类类型[ Note :这样的类可能有一个非平凡的析构函数-尾注]。

A constant initializer for an object o is an expression that is a constant expression, except that it may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types [Note: such a class may have a non-trivial destructor — end note].

所以回顾一下:在C ++ 14中, constexpr 有两个用途:

So to recap: As of C++14, constexpr has two uses:


  1. C ++ 11解释:常量表达式是与其值相同的表达式(即其评估没有副作用); constexpr 变量只是其值的占位符,并不打算用于它们的对象标识,通常期望常量表达式可以用它们的(编译时)自由替换。

  1. The C++11 interpretation: a "constant expression" is an expression that is identical to its value (i.e. its evaluation has no side effects); constexpr variables are just placeholders for their value and not intended to be used for their object identity, and it is generally expected that constant expressions can be freely replaced with their (compile-time knowable) value.

C ++ 14 constexpr 函数,包括构造函数:这些函数,包括可以在静态初始化阶段调用构造函数,以使用静态存储持续时间对变量进行常量初始化。如果变量是对象,则它们仍然保留其对象标识,可能需要动态销毁,但是它们的初始化发生在任何动态初始化之前,并且不受顺序限制。

The C++14 constexpr functions, including constructors: These functions, including constructors, may be called in the static initialization phase to constant-initialize variables with static storage duration. If the variables are objects, they still retain their object identity and may need dynamic destruction, but their initialization happens before any dynamic initialization and is not subject to ordering.

这篇关于派生类中用于空初始化构造函数的constexpr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆