有什么能阻止 std::optional::value_or() 有条件地 noexcept 吗?

Does anything prevent std::optional::value_or() from being conditionally noexcept?

这是 C++17 标准中 value_or() 的定义:

template <class U> constexpr T value_or(U&& v) const&;

Effects: Equivalent to:

return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));

Remarks: If is_copy_constructible_v<T> && is_convertible_v<U&&, T> is false, the program is ill-formed.

(右值重载类似)

value_or的效果被描述为等同于return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));

operator boolnoexceptoperator*not noexcept (即使它没有抛出,可能是因为如果在可选不包含值时使用它仍然会因 UB 而失败) .但是,我们保证永远不会尝试 return 包含的值,除非我们有一个。

所以不能 value_or 声明 noexcept 给定 is_nothrow_copy_constructible<T> && noexcept(static_cast<T>(std::forward<U>(v)))

is used extremely sparingly in the 标准。这是唯一的障碍。


虽然这回答了问题,但下一个问题是“为什么很少使用它”。这是您可能会觉得有用的额外信息;如果这是答案的核心,我会包含更多引号而不是链接。纸质编号应该比我使用的特定超链接更有效,所以就是这样。

N3279 是关于 noexcept 的讨论的结论。基本上,任何具有窄合同(可以展示 UB)并且不是移动 ctor 或 dtor 的东西都不会被标记为 noexcept。

指南如下:

Adopted Guidelines

  • No library destructor should throw. They shall use the implicitly supplied (non-throwing) exception specification.
  • Each library function having a wide contract, that the LWG agree cannot throw, should be marked as unconditionally noexcept.
  • If a library swap function, move-constructor, or move-assignment operator is conditionally-wide (i.e. can be proven to not throw by applying the noexcept operator) then it should be marked as conditionally noexcept. No other function should use a conditional noexcept specification.
  • Library functions designed for compatibility with “C” code (such as the atomics facility), may be marked as unconditionally noexcept.

我没有参与讨论,但基本想法是编译器可以向这些方法添加异常

我相信这就是所谓的 Lakos 规则。要更改它,请与委员会讨论。

N3248 是提出 noexcept 问题的论文。主要是关于测试。