异常规范的评估点

时间:2018-05-20 11:07:35

标签: c++ language-lawyer c++17 noexcept

请考虑以下代码段:

版本(1)

void q() {}
class B {
  void f() noexcept(noexcept(q())) {q(); }
  decltype(&B::f) f2;
};

版本(2)

void q() {}
class B {
  void f() noexcept(true) {q(); }
  decltype(&B::f) f2;
};

版本(3)

void q() {}
class B {
  void f() noexcept {q(); }
  decltype(&B::f) f2;
};

所有版本的GCC都会编译这些代码片段而不会出现任何错误或警告(包括trunk-version)。支持C ++ 17的所有版本的Clang拒绝版本(1)和(2),但没有版本(3),但有以下错误:

<source>:4:16: error: exception specification is not available until end of class definition

  decltype(&B::f) f2;

               ^

考虑到标准将noexcept定义为等同于noexcept(true) [except.spec]。因此,版本(2)和版本(3)应该是等价的,它们不适用于clang。

因此,以下问题:在哪一点上需要根据C ++ 17标准评估异常规范?并且,如果上面的某些代码无效,背后的理性是什么?

感兴趣的人的抽象背景:

template <typename F>
struct result_type;

template<typename R, typename C, typename... Args>
struct result_type<R(C::*)(Args...)> {
  using type = R;
}; // there may be other specializations ...

class B {
  int f() noexcept(false) { return 3; }
  typename result_type<decltype(&B::f)>::type a;
};

此代码至少应该在C ++ 14之前有效,因为noexcept不是函数类型的一部分(对于clang,它编译为版本3.9.1)。对于C ++ 17,无法执行此操作。

2 个答案:

答案 0 :(得分:5)

这是CWG 1330的结果。

基本上,该类在其 noexcept-specifier 中被认为是完整的(在上面的缺陷的解析中称为 exception-specification )。 / p>

这使我们处于以下情况:

void q() {}
class B {
  void f() noexcept(noexcept(q())) {q(); }
//                  ~~~~~~~~~~~~~
//                  evaluated in the context of complete B

  decltype(&B::f) f2;
//~~~~~~~~~~~~~~~
//cannot wait until B is complete to evaluate
};

我们需要知道decltype(&B::f)来处理B::f2的声明,但为了知道该类型,我们需要知道{em> noexcept-specifier 的内容{ {1}}是(因为现在它是类型系统的一部分),但是为了那个,我们需要在上下文中评估 noexcept-specifier 。完成B::f

该程序格式不正确,铿锵是正确的。

答案 1 :(得分:0)

我将自己参考所有相关资源来回答这个问题。

让我引用Richard Smith来说明为什么这是一个缺陷,以及为什么所有示例都格式错误,因为异常说明仅在类的末尾进行解析。

  

使用Clang拒绝该代码大致正确。

     

对于每个C ++ DR1330,直到我们到达类的末尾(它们可以命名稍后声明的类成员,并且该类在其中完成),才会解析异常规范,就像成员函数体,默认成员初始化器,和默认参数。

     

最后,还有C ++ DR361(可悲的是,在提交后仍然开放16年),其中CWG的结论是,如果您在课程结束之前使用延迟分析的构造,则该程序格式不正确。但是我们还没有实际的标准措辞来支持这一点,只是没有解决该缺陷就无法实现的标准。

LLVM Bug 37559,但另请参见Google GroupsCWG 361CWG 1330

此外,如[except.spec]中所述,noexcept原则上应完全等同于noexcept(true),并且接受noexcept显然是错误的,但拒绝{{1 }}。

因此,结论是所有示例都是错误的,即使这不是理想的行为。