[expr.unary.noexcept]的措词已在[[C ++ 17中更改<<C ++ 20]) 。
以前(n4140, 5.3.7 noexcept operator [expr.unary.noexcept]),noexcept运算符的结果为false,如果在可能评估的上下文中表达式将包含(3.1)对函数,成员函数的可能评估的调用,函数指针或不具有成员的成员函数指针非抛出异常规范([except.spec]),
(7.6.2.6 noexcept operator [expr.unary.noexcept]):现在1
noexcept运算符的结果为true,除非表达式可能被抛出([except.spec])。
如果函数的声明没有noexcept-specifier,则该声明具有可能引发的异常规范,除非...
但是14.5(3)的除非列表没有列出
constexpr
,因此可能会抛出...[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
每个规范的正确行为是什么?
noexcept
函数上的constexpr
推论影响this trick] ..
[expr.unary.noexcept]的措词在C ++ 17中已更改(在@ L.F。评论后编辑:C ++ 20)。以前(n4140,5.3.7 noexcept运算符[expr.unary.noexcept]),我的重点是:...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
noexcept
添加了一种特殊情况用于常量表达式,因此:constexpr void f() {} static_assert(noexcept(f()));
CWG 1351(以C ++ 14结尾)在措辞上有了很大的改变,但特例仍然以另一种形式出现。P0003R5(在C ++ 17中结束)再次更改了措辞,但是特殊情况被删除(偶然),所以现在:
当前,clang做对了C ++ 17的错误(故意导致C ++ 14和C ++ 11失败)。 g ++,但是,已经为C ++ 11实现了特殊情况,但尚未实现对于C ++ 17进行更改。当前,icc和msvc的行为类似于g ++。constexpr void f() {} static_assert(!noexcept(f()));
[[[根据LLVM 15481中的Richard Smith,CWG对此进行了讨论,但决定将其行为保持原样。
Clang Bug 15481 - noexcept should check whether the expression is a constant expression
您尽一切努力避免在深度嵌套的情况下二次运行表达式?
[...]换句话说,P0003意外删除了特殊规则,但CWG决定保留该删除规则。CWG讨论的结论:我们将保持原样。
noexcept
对于常量表达式没有特殊的规则。事实证明,这对于适当的图书馆实际上是必不可少的功能:例如,如果
noexcept
尝试评估其操作数,则(例如)通过使is_nothrow_swappable
断开std::swap
constexpr
,因为然后std::swap<T>
常常最终变得在T
完成之前实例化。因此,我还将考虑将此更改视为针对C ++ 11和C ++ 14的有效DR ...但我愿意重新考虑如果我们看到许多用户投诉。