According to cppreference constructor (2) of std::span
is defined as
template< class It >
explicit(extent != std::dynamic_extent)
constexpr span( It first, size_type count );
with its exceptions listed as 2) Throws nothing.
If this constructor "throws nothing" then why is it even listed under exceptions and why is the constructor not marked noexcept?
That's because this constructor has preconditions. From the standard:
template<class It>
constexpr explicit(extent != dynamic_extent) span(It first, size_type count);
Constraints: Let U be remove_reference_t<iter_reference_t>.
- It satisfies contiguous_iterator.
- is_convertible_v<U()[], element_type()[]> is true.
[Note 1: The intent is to allow only qualification conversions of the iterator reference type to element_type. — end note]Preconditions:
- [first, first + count) is a valid range.
- It models contiguous_iterator.
- If extent is not equal to dynamic_extent, then count is equal to extent.
Effects: Initializes data_ with to_address(first) and size_ with count.
Throws: Nothing.
Functions with preconditions that "throw nothing" aren't marked noexcept
because undefined behavior can occur if these preconditions aren't fulfilled. For example, std::vector::front
isn't marked noexcept
even though there is no way it would throw, but calling it on an empty vector is undefined behavior.
Here is a paper about it: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1656r1.html