9

Here's the definition of value_or() from the C++17 standard:

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.

(the rvalue overload is similar)

The effect of value_or is described as equivalent to return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));

operator bool is noexcept. operator* is not noexcept (even though it doesn't throw, probably because it can still fail with UB if used when the optional does not contain a value). However, we are guaranteed to never try to return the contained value unless we have one.

So couldn't value_or be declared noexcept given is_nothrow_copy_constructible<T> && noexcept(static_cast<T>(std::forward<U>(v)))?

Mgetz
  • 5,108
  • 2
  • 33
  • 51
knatten
  • 5,191
  • 3
  • 22
  • 31

1 Answers1

7

is used extremely sparingly in the standard. That is about the only barrier.


While this answers the question, the next question is "why is it used sparingly". This is an extra bit of information you might find useful; if this was the core of the answer, I'd include more quotes instead of links. The paper numbers should outlive the specific hyperlinks I'm using, so there is that.

N3279 is the conclusion of a discussion about noexcept. Basically, anything with a narrow contract (that can exhibit UB) and isn't a move ctor or dtor is never marked noexcept.

Here are the guidelines:

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.

I wasn't party to the discussion, but basically the idea is that the compiler can add exceptions to those methods.

I believe this is called the Lakos rule. To change it, take it up with the committee.

N3248 is the paper that brought up issues with noexcept. Mostly it is about testing.

Community
  • 1
  • 1
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • 3
    Relevant guideline to this question is on page 2: only `swap()` and move constructorsassignments in the library are conditionally noexcept. – Barry May 03 '18 at 20:02
  • 1
    At the previous committee meeting, I think that they agreed to make "wrapper types" conditionally `noexcept` based on the operations of the types they wrap. `std::optional` and `std::variant` would be such wrapper types. – Morwenn May 03 '18 at 20:40
  • This is a good answer for any "Why is X not noexcept" question – kmdreko May 03 '18 at 21:00
  • @morwenn do you have documentation or links to that effect so I can insert a quote with attribution? – Yakk - Adam Nevraumont May 04 '18 at 01:18
  • @Morwenn what do you mean by making the type conditionally `noexcept`? Are you referring to any particular operations on them in particular? In c++17, `optional(optional&& rhs)` is already `noexcept` if `is_nothrow_move_constructible_v` (and similar for move assignment). `variant` does the same, but it has to hold for all the wrapped types. – knatten May 04 '18 at 07:31
  • 1
    @Yakk The paper I was mentioning was [P0884 - Extending the `noexcept` Policy](https://wg21.link/P0884], which is actually rather terse. The paper cites `std::atomic` and the proposed `std::function_ref` as examples of wrapping types. I just checked the meeting minutes (non public) and the question was raised about `std::optional` and `std::variant` but the actual answer was that the aim of the paper was to broaden the conditional `noexcept` policy not to make firm decisions, so no definite answer for those types. Apparently the committee was strongly for accepting this paper. – Morwenn May 04 '18 at 07:37
  • 2
    @knatten Just rechecked the paper again and it actually only proposes conditional `noexcept` for the default constructor, copy constructor and copy assignment operator of wrapper types, so unlike what I thought there is no way it affects `value_or`, sorry :/ – Morwenn May 04 '18 at 07:39