为什么 N3421 不提供 noexcept 限定符?

Why doesn't N3421 provide the noexcept qualifier?

本文关键字:noexcept N3421 为什么      更新时间:2023-10-16

在N3421中-使运算符函数更大<>,std函数对象的新专业化是:

template <> struct plus<void> {
template <class T, class U> auto operator()(T&& t, U&& u) const
-> decltype(std::forward<T>(t) + std::forward<U>(u));
};

而不是

template <> struct plus<void> {
template <class T, class U> auto operator()(T&& t, U&& u) const
noexcept(noexcept(decltype(std::forward<T>(t) + std::forward<U>(u))
(std::move(std::forward<T>(t) + std::forward<U>(u)))))
-> decltype(std::forward<T>(t) + std::forward<U>(u));
};
  • 这有什么原因吗
  • noexcept的省略在这个用例中重要吗

Edit:链接到github中的工作草稿行。

编辑2:链接到libc++加专业化。

现有的LWG指南不鼓励使用noexcept。他们不接受广义合同职能的例外情况,只接受狭义合同职能。我不记得这些术语是如何定义的,但我可以告诉你,我参加了布里斯托尔会议,讨论noexcept,他们拒绝将其放在函数中,因为这是一个广泛的合同,我认为这是疯狂的。

所以它可能不在这里,原因有两个。首先,委员会和论文作者还不习惯在每种情况下都考虑noexcept——类似于constexpr。在这种情况下,论文作者(STL)可能只是忘记添加它

第二,LWG对何时接受noexcept有一些疯狂的过度限制。

@DeadMG的回答让我在图书馆中保守地使用了noexcept,它说:

采用的指南

  • 任何库析构函数都不应该抛出。它们应该使用隐式提供的(非抛出的)异常规范。

  • 每个库函数都有一个宽协定,LWG同意不能抛出,应该标记为无条件noexcept。

  • 如果库交换函数、移动构造函数或移动赋值运算符是有条件宽的(即可以证明不会抛出应用noexcept运算符),则应将其标记为有条件无例外。任何其他函数都不应使用条件无异常规范。

  • 为与"C"代码兼容而设计的库函数(如原子功能)可能被标记为无条件noexcept。

其中狭义和广义合约定义为:

  • 函数或操作的广泛契约不会指定任何未定义的行为。这样的合同没有任何先决条件:使用宽合约时,不会对其自变量,在任何对象状态上,也不在任何外部全局状态上。

  • 狭义合同是指不广泛的合同。函数或操作的狭义契约在调用时会导致未定义的行为以违反书面合同的方式。这样的合同指定至少一个涉及其参数、对象的前提条件状态,或某些外部全局状态,例如静态对象。

在该文档的末尾,先前标记为noexcept的运算符函子不再是noexcept

因此,如果我理解正确的话,<functional>中的新运算符函子有广泛的约定,但有时可能会抛出,这取决于它们所作用的类型。因此,它们不是无条件的noexcept(true)。因此,由库实现者来决定:

它们的使用作为库供应商的实现质量功能,直到我们有更多的经验。