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

sky*_*ack 12 c++ language-lawyer noexcept c++11 inheriting-constructors

我不确定这是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{};
}
Run Code Online (Sandbox Code Playgroud)

如果noexcept删除它,它编译.
无论如何,正如在例子中,我从GCC v5.3.1得到了这个错误:

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

据我所知,struct D不是一个不完整的类型,但继承构造函数涉及到语句,看起来编译器实际上考虑的是基本结构的完整性而B不是D.

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

为清楚起见:

  • 这里使用clang 3.7.1编译成功
  • 这里使用GCC 5.3.0进行编译失败

有关更多详细信息,请参阅此链接以获取GCC编译器的bugzilla.
目前,该错误仍未得到证实.我会尽快更新问题.

Geo*_*ard 12

您的代码是合法的,即使海湾合作委员会另有说法.这个看起来很滑稽的宣言违反了它:

D() noexcept(noexcept(D{42}));
Run Code Online (Sandbox Code Playgroud)

最外面的noexcept是一个noexcept说明符,D::D()当且仅当其constant-expression参数的计算结果为true时,表示noexcept.inner noexcept是一个noexcept运算符,它在编译时检查它的参数表达式(实际上没有被计算)是否会抛出异常.因为D::D(int)是noexcept(继承自B),所以这应该是真的.

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

noexcept运算符执行编译时检查,如果声明表达式不抛出任何异常,则返回true.

它可以在函数模板的noexcept说明符中使用,以声明该函数将为某些类型而不是其他类型抛出异常.

现在,由于标准的§9.2.2(添加了大胆的重点),该类应该在noexcept说明符中被认为是完整的:

}类说明符结束时,类被视为完全定义的对象类型(3.9)(或完整类型).在类成员规范中,该类在函数体,默认参数,using-declaration中被认为是完整的,为非静态数据引入了继承构造函数(12.9),异常规范 s大括号或大小写器.成员(包括嵌套类中的这些东西).否则,它在其自己的类成员规范中被视为不完整.

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

异常规范:

  • 动态异常规范

  • noexcept规格

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