This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4409. Constant expression ranges::size(r) Constraints and Mandates in [simd]

Section: 29.10 [simd] Status: New Submitter: Lénárd Szolnoki Opened: 2025-10-10 Last modified: 2025-10-12

Priority: Not Prioritized

View all issues with New status.

Discussion:

Various Constraints and Mandates in 29.10 [simd] are conditioned on ranges::size(r), assuming that subsequent operations on the result are also constant expression. This is not a given, since ranges::size(r) is allowed to return an integer-class type, and it is not mandated that operations on integer-class types are usable in constant expressions.

In particular:

  1. 29.10.7.2 [simd.ctor] p13:

    Constraints:

    • R models ranges::contiguous_range and ranges::sized_range,

    • ranges::size(r) is a constant expression, and

    • ranges::size(r) is equal to size().

    Here ranges::size(r) == size() might not be a constant expression, even when ranges::size(r) is. Operations that are not accounted for:

  2. 29.10.7.2 [simd.ctor] p17+18:

    Constraints:

    • R models ranges::contiguous_range and ranges::sized_range, and

    • ranges::size(r) is a constant expression

    Remarks: The deduced type is equivalent to vec<ranges::range_value_t<R>, ranges::size(r)>.

    Here the second constraint is simply redundant, if failure to form the type is in the immediate context. If we want to type it out in the constraints then we should account for conversion to simd-size-type and narrowing.

  3. 29.10.8.7 [simd.loadstore] p2:

    Mandates: If ranges::size(r) is a constant expression then ranges::size(r)V::size().

    Here ranges::size(r) >= V::size() might not be a constant expression, even when ranges::size(r) is. It is unclear why a mathematical operator symbol is used here (and further down in the preconditions).

Proposed resolution:

This wording is relative to N5014.

  1. Modify 29.10.7.2 [simd.ctor] as indicated:

    template<class R, class... Flags>
      constexpr basic_vec(R&& r, flags<Flags...> = {});
    template<class R, class... Flags>
      constexpr basic_vec(R&& r, const mask_type& mask, flags<Flags...> = {});
    

    -12- Let mask be mask_type(true) for the overload with no mask parameter.

    -13- Constraints:

    1. (13.1) — R models ranges::contiguous_range and ranges::sized_range, and

    2. (13.2) — ranges::size(r) == size() is a constant expression, and evaluates to true.

    3. (13.3) — ranges::size(r) is equal to size().

    […]
    template<class R, class... Ts>
      basic_vec(R&& r, Ts...) -> see below;
    

    -17- Constraints:

    1. (17.1) — R models ranges::contiguous_range and ranges::sized_range, and.

    2. (17.2) — ranges::size(r) is a constant expression.

    -18- Remarks: The deduced type is equivalent to vec<ranges::range_value_t<R>, ranges::size(r)>.

  2. Modify 29.10.8.7 [simd.loadstore] as indicated:

    template<class V = see below, ranges::contiguous_range R, class... Flags>
      requires ranges::sized_range<R>
      constexpr V unchecked_load(R&& r, flags<Flags...> f = {});
    […]
    template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
      constexpr V unchecked_load(I first, S last, const typename V::mask_type& mask,
                                 flags<Flags...> f = {});
    

    -1- Let […]

    -2- Mandates: If ranges::size(r) >= V::size() is a constant expression then ranges::size(r)V::size()it evaluates to true.