noexcept,继承构造函数和对实际上完整的不完整类型的无效使用

noexcept, inheriting constructors and the invalid use of an incomplete type that is actually complete

我不确定这是 GCC 编译器的错误还是 noexcept.
的预期行为 考虑以下示例:

struct B {
    B(int) noexcept { }
    virtual void f() = 0;
};

struct D: public B {
    using B::B;
    D() noexcept(noexcept(D{42})): B{42} { }
    void f() override { }
};

int main() {
    B *b = new D{};
}

如果删除 noexcept,它会编译。
无论如何,就像在示例中一样,我从 GCC v5.3.1 得到了这个错误:

test.cpp:8:31: error: invalid use of incomplete type ‘struct D’
     D() noexcept(noexcept(D{42})): B{42} { }
                               ^

据我所知,struct D 不是一个不完整的类型,但是声明中涉及继承构造函数,看起来编译器实际上正在考虑基本结构的完整性 B超过 D.

这是预期行为还是合法代码?

为了清楚起见:

有关 GCC 编译器的 bugzilla,请参阅 this link 了解更多详细信息。
目前,该错误仍未得到证实。我会尽快更新问题。

您的代码是合法的,即使 GCC 另有声明。它冒犯了这个看起来很滑稽的声明:

D() noexcept(noexcept(D{42}));

最外层的 noexcept 是一个 noexcept specifier, stating that D::D() is noexcept if and only if its constant-expression argument evaluates to true. The inner noexcept is a noexcept operator,它在编译时检查其参数表达式(实际上未计算)是否不抛出异常。因为D::D(int)是noexcept(继承自B),所以应该是这样。

cppreference.com 明确指出允许在说明符内使用运算符(强调已添加):

The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions.

It can be used within a function template's noexcept specifier to declare that the function will throw exceptions for some types but not others.

现在,由于标准的 §9.2.2(添加了粗体强调),在 noexcept 说明符中 class 应被视为 complete

A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

§15.4.1 将 异常规范 定义为以下语法:

exception-specification:

  • dynamic-exception-specification

  • noexcept-specification

所以 GCC 不应该拒绝你的代码。