Why std::any & operator= for ValueType is not conditionally noexcept?

Viewed 159

The question is quite simple.

This is the declaration of templated operator= for std::any:

template<typename ValueType>
any& operator=( ValueType&& rhs );

I would expect it to be:

template<typename ValueType>
any& operator=( ValueType&& rhs ) noexcept(noexcept(std::declval<std::any>() = std::forward<ValueType>(std::declval<ValueType>()));

Namely, if you can copy-assign ValueType to any in a noexcept fashion, then you should be able to have noexcept.

Maybe I am missing something.

2 Answers

The literal answer is that such a specification would be recursive (you're saying the assignment should be noexcept if the assignment is noexcept).

But the probably more useful answer is that since any may have to allocate, you could only really have noexcept assignment in the case that decay_t<ValueType> is

  • sufficiently small (so as to not need allocation), and
  • nothrow move constructible, and
  • nothrow constructible from ValueType

The only way to specify the noexcept condition would require you to also specify what "sufficiently small" means - which would limit implementation freedom, for questionable gain.

The standard library doesn't typically use conditional noexcept - so why would this be the... exception?

template<class T> any& operator=(T&& rhs);

[any.assign]/12 - Throws: Any exception thrown by the selected constructor of VT.

The overload you showed only participate in overload resolution if ValueType is copy constructible, which leave the door open for the copy construction of ValueType to throw during the std::any assignment.

Note that you're also showing a noexcept specification defined in terms of the same operation being defined.

Related