constexpr函数的noexcept行为

问题描述 投票:6回答:1

[expr.unary.noexcept]的措词已在[[C ++ 17中更改<<C ++ 20]) 。

以前(n4140, 5.3.7 noexcept operator [expr.unary.noexcept]),我的重点:

noexcept运算符的结果为false,如果在可能评估的上下文中表达式将包含

    (3.1)对函数,成员函数的可能评估的调用,函数指针或不具有成员的成员函数指针非抛出异常规范([except.spec]),
  1. 除非调用是一个常量表达式([expr.const]) ...

现在1

7.6.2.6 noexcept operator [expr.unary.noexcept]):

noexcept运算符的结果为

true,除非表达式可能被抛出([except.spec])。
    然后在14.5 Exception specifications [except.spec]中:

  • 如果函数的声明没有noexcept-specifier,则该声明具有可能引发的异常规范,除非...

  • 但是14.5(3)的
      除非列表没有列出constexpr,因此可能会抛出...
    1. [1指向L.F.在注释中添加的C ++ 17 n4659的链接。

    测试代码constexpr int f(int i) { return i; } std::cout << boolalpha << noexcept(f(7)) << std::endl; int a = 7; std::cout << boolalpha << noexcept(f(a)) << std::endl;


    用于打印(with gcc 8.3):

    true false
    都使用

    -std = c ++ 11和

    -std = c ++ 2a编译

    但是现在打印相同的代码(with gcc 9.2):


    false false

    都使用-std = c ++ 11

    -std = c ++ 2a编译

    顺便说一下,Clang非常一致,since 3.4.1,并附带:

    false false


    每个规范的正确行为是什么?
      规格上是否有真正的变化?如果是这样,此更改的原因是什么?
    • 如果规范中的更改影响或与过去的行为相矛盾,强调更改及其含义是否是一种惯例?如果更改为
    • 不强调,是否可以暗示它可能是
    • 监督?
    • 如果这是真正的预期更改,是否将其视为应该回溯到规范的早期版本的错误修复,编译器是否正确地将新行为追溯到C ++ 11?

  • 侧面说明: noexcept函数上的constexpr推论

    影响this trick] ..

    [expr.unary.noexcept]的措词在C ++ 17中已更改(在@ L.F。评论后编辑:C ++ 20)。以前(n4140,5.3.7 noexcept运算符[expr.unary.noexcept]),我的重点是:...
  • c++ c++17 language-lawyer constexpr noexcept
    1个回答
    5
    投票
    每个规范的正确行为是什么?

    C ++ 17之前的[true false,C ++ 17以后的false false

    规格上是否有真正的变化?如果是这样,此更改的原因是什么?

    是。请参阅下面的Clang错误报告中的报价。

    [如果规格发生变化,从而影响或矛盾过去行为,强调改变和它的含义?如果不强调更改,是否可以暗示它可能是疏忽?

    是;是的(但CWG后来发现有理由证明监督的合理性,因此保持原样)。

    如果这是真正的预期更改,是否认为该错误修复程序是应该回到规范的先前版本,编译器正确吗将新行为追溯地与C ++ 11对齐?

    我不确定。请参阅下面的Clang错误报告中的报价。

    详细

    我已经搜索了很多地方,到目前为止,我能找到的最接近的地方是对相关错误报告的评论:

    GCC Bug 87603 - [C++17] noexcept isn't special cased for constant expressions anymore

    • CWG 1129(在C ++ 11中结束)为noexcept添加了一种特殊情况用于常量表达式,因此:

      constexpr void f() {} static_assert(noexcept(f()));

      CWG 1351(以C ++ 14结尾)在措辞上有了很大的改变,但特例仍然以另一种形式出现。

      P0003R5(在C ++ 17中结束)再次更改了措辞,但是特殊情况被删除(偶然),所以现在:

      constexpr void f() {} static_assert(!noexcept(f()));
      

      [[[根据LLVM 15481中的Richard Smith,CWG对此进行了讨论,但决定将其行为保持原样。

      当前,clang做对了C ++ 17的错误(故意导致C ++ 14和C ++ 11失败)。 g ++,但是,已经为C ++ 11实现了特殊情况,但尚未实现对于C ++ 17进行更改。当前,icc和msvc的行为类似于g ++。

      Clang Bug 15481 - noexcept should check whether the expression is a constant expression
    • wg21.link/p0003删除了常量表达式的特殊情况-显然是偶然的。我正在调查是否会保持不走。
    • 您尽一切努力避免在深度嵌套的情况下二次运行表达式?

      [...]

      CWG讨论的结论:我们将保持原样。 noexcept对于常量表达式没有特殊的规则。

      事实证明,这对于适当的图书馆实际上是必不可少的功能:例如,如果noexcept尝试评估其操作数,则(例如)通过使is_nothrow_swappable断开std::swapconstexpr,因为然后std::swap<T>常常最终变得在T完成之前实例化。

      因此,我还将考虑将此更改视为针对C ++ 11和C ++ 14的有效DR ...但我愿意重新考虑如果我们看到许多用户投诉。

      换句话说,P0003意外删除了特殊规则,但CWG决定保留该删除规则。
    © www.soinside.com 2019 - 2024. All rights reserved.