12

我不确定这是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.

这是预期的行为还是法律法规?

为清楚起见:

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

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

4

1 回答 1

12

您的代码是合法的,即使 GCC 另有声明。它对这个看起来很有趣的声明感到冒犯:

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

最外层noexcept是一个noexcept 说明符,表示D::D()当且仅当它的常量表达式参数的计算结果为 true 时,它​​才是 noexcept。innernoexcept是一个noexcept 运算符,它在编译时检查其参数表达式(实际上并未计算)是否不引发异常。因为D::D(int)是noexcept(继承自B),这应该是真的。

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

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

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

现在,由于标准的第 9.2.2 节,该类应该在 noexcept 说明符内被认为是完整的(添加了粗体强调):

}class-specifier结束时,类被视为完全定义的对象类型 (3.9)(或完整类型)。在类member-specification中,该类在函数体、默认参数、引入继承构造函数 (12.9)、exception-specification和用于非静态数据的括号或等式初始化器中的类被认为是完整的成员(包括嵌套类中的此类内容)。否则,它在其自己的类成员规范中被视为不完整。

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

异常规范

  • 动态异常规范

  • noexcept 规范

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

于 2016-03-04T07:50:04.700 回答