2

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?

Chris_F
  • 4,991
  • 5
  • 33
  • 63

1 Answers1

10

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

Nelfeal
  • 12,593
  • 1
  • 20
  • 39
  • Unless I am mistaken that paper is arguing that the standard should be changed so that these narrow contract functions would be marked noexcept. – Chris_F Nov 06 '22 at 14:17
  • 1
    @Chris_F Yes, but it also explains why the current situation is what it is. Standardization takes time. – Nelfeal Nov 06 '22 at 14:19