4

N3421 - Making Operator Functors Greater<>中,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在这个用例中是否有遗漏?

编辑:链接到 github 中的工作草案行

编辑 2:链接到 libc++ plus specialization

4

2 回答 2

6

现有的 LWG 指南不鼓励使用 noexcept。他们不接受宽合约函数的 noexcept,只接受窄合约函数。我不记得这些术语是如何定义的,但我可以告诉你,我出席了布里斯托尔会议的讨论noexcept,他们拒绝将它放在一个函数上,因为它是广泛的合同,我认为这太疯狂了。

因此,由于两个原因之一,它可能不在此处。首先是委员会和论文作者还没有习惯noexcept在每个案例中都考虑类似的情况constexpr。在这种情况下,论文作者 (STL) 可能只是忘记添加它。

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

于 2014-02-13T14:00:43.250 回答
4

@DeadMG 的回答让我在 Library 中保守地使用 noexcept,其中说:

采用的准则

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

  • LWG 同意不能抛出的具有广泛合同的每个库函数都应标记为无条件 noexcept。

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

  • 为与“C”代码(例如 atomics 工具)兼容而设计的库函数可以无条件标记为 noexcept。

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

  • 函数或操作的广泛契约没有指定任何未定义的行为。这样的契约没有先决条件:具有广泛契约的函数对其参数、任何对象状态或任何外部全局状态都没有额外的运行时约束。

  • 狭义合同是不广泛的合同。当以违反记录合同的方式调用时,函数或操作的狭窄合同会导致未定义的行为。这样的契约至少规定了一个先决条件,涉及其参数、对象状态或一些外部全局状态,例如静态对象的初始化。

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

因此,如果我正确理解这一点,新的操作符函子<functional>具有广泛的合同,但有时可能会根据它们所作用的类型而抛出。因此,它们不是无条件的noexcept(true)。因此,由库实现者决定:

在我们有更多经验之前,它们的使用将作为库供应商的实施质量功能。

于 2014-02-13T14:18:20.300 回答