3101. span's Container constructors need another constraint

Section: 23.7.2.2.2 [span.cons] Status: C++20 Submitter: Stephan T. Lavavej Opened: 2018-04-12 Last modified: 2021-02-25

Priority: 1

View all other issues in [span.cons].

View all issues with C++20 status.

Discussion:

When I overhauled span's constructor constraints, I was careful about the built-in array, std::array, and converting span constructors. These types contain bounds information, so we can achieve safety at compile-time by permitting implicit conversions if and only if the destination extent is dynamic (this accepts anything by recording the size at runtime) or the source and destination extents are identical. However, I missed the fact that the Container constructors are the opposite case. A Container (e.g. a vector) has a size that's known only at runtime. It's safe to convert this to a span with dynamic_extent, but for consistency and safety, this shouldn't implicitly convert to a span with fixed extent. (The more verbose (ptr, count) and (first, last) constructors are available to construct fixed extent spans from runtime-length ranges. Note that debug precondition checks are equally possible with the Container and (ptr, count)/(first, last) constructors. The issue is that implicit conversions are notoriously problematic, so they should be permitted only when they are absolutely known to be safe.)

[2018-04-24 Priority set to 1 after discussion on the reflector.]

[2018-06 Rapperswil Thursday issues processing]

Status to LEWG. Should this be ill-formed, or fail at runtime if the container is too small? Discussion on the reflector here.

[2018-11 San Diego Saturday]

LEWG said that they're fine with the proposed resolution. Status to Tentatively Ready.

Proposed resolution:

This wording is relative to N4741.

  1. Edit 23.7.2.2.2 [span.cons] as indicated:

    template<class Container> constexpr span(Container& cont);
    template<class Container> constexpr span(const Container& cont);
    

    -14- Requires: [data(cont), data(cont) + size(cont)) shall be a valid range. If extent is not equal to dynamic_extent, then size(cont) shall be equal to extent.

    -15- Effects: Constructs a span that is a view over the range [data(cont), data(cont) + size(cont)).

    -16- Postconditions: size() == size(cont) && data() == data(cont).

    -17- Throws: What and when data(cont) and size(cont) throw.

    -18- Remarks: These constructors shall not participate in overload resolution unless:

    1. (18.?) — extent == dynamic_extent,

    2. (18.1) — Container is not a specialization of span,

    3. (18.2) — Container is not a specialization of array,

    4. […]