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