Why doesn't N3421 provide the noexcept qualifi

2019-02-18 11:34发布

问题:

In N3421 - Making Operator Functors greater<>, the new specialization for the std function objects is:

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));
};

instead of

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));
};
  • Is there a reason for that?
  • Does the omission of noexcept matter in this use case?

Edit: link to the working draft line in github.

Edit 2: link to libc++ plus specialization.

回答1:

The existing LWG guidelines do not encourage the use of noexcept. They do not accept noexcept on wide-contract functions, only narrow-contract ones. I don't recall exactly how these terms were defined, but I can tell you that I was present at the Bristol meeting discussing noexcept and they refused to place it on a function because it was wide-contract, which I considered to be batshit insane.

So it's probably not on here for one of two reasons. The first is that the Committee and paper authors are not yet used to considering noexcept in every case- similar to constexpr. In this case, the paper author (STL) probably simply forgot to add it.

The second is that LWG has some insane over-restrictions on when they will accept noexcept.



回答2:

@DeadMG's answer led me to Conservative use of noexcept in the Library, which says the following:

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.

where narrow and wide contracts are defined as:

  • A wide contract for a function or operation does not specify any undefined behavior. Such a contract has no preconditions: A function with a wide contract places no additional runtime constraints on its arguments, on any object state, nor on any external global state.

  • A narrow contract is a contract which is not wide. Narrow contracts for a functions or operations result in undefined behavior when called in a manner that violates the documented contract. Such a contract specifies at least one precondition involving its arguments, object state, or some external global state, such as the initialization of a static object.

At the end of that document, operators functors previously marked noexcept are no longer noexcept.

So if I understand this correctly, the new operators functors in <functional> have wide-contracts, but might throw sometimes depending on the types they act on. As such, they are not unconditionally noexcept(true). Due to this, it is left to the library implementors to decide:

their use be left as a library vendor quality-of-implementation feature until we have more experience.