### 3614. `iota_view::size` and the most negative signed integer values

**Section:** 26.6.4.2 [range.iota.view] **Status:** New
**Submitter:** Jiang An **Opened:** 2021-10-01 **Last modified:** 2021-10-14 11:34:59 UTC

**Priority: **3

**View other** active issues in [range.iota.view].

**View all other** issues in [range.iota.view].

**View all issues with** New status.

**Discussion:**

According to 26.6.4.2 [range.iota.view]/15, when both `W` and `Bound` are
integer-like, the expression in the return statement uses `-`*value_* and `-`*bound_*.
These operations result in undefined behavior when `-` is applied to the most negative integer
value of a promoted type.

I believe that we can simply convert *value_* and *bound_* to the return type
(*make-unsigned-like-t*<common_type_t<W, Bound>>) and then perform the subtraction.
Such method should give the same results with UB eliminated.

Additionally, if we decide that `iota_view<uint8_t, uint8_t>(uint8_t(1)).size()` is well-defined
(LWG 3597), it should give the correct result. We can truncate the result to fit the type `W`.

*[2021-10-14; Reflector poll]*

Set priority to 3 after reflector poll.

**Proposed resolution:**

This wording is relative to N4892.

[*Drafting Note:* Two mutually exclusive options are prepared, depicted below by **Option A** and
**Option B**, respectively.]

**Option A:** Just fixes the most negative values

Modify 26.6.4.2 [range.iota.view] as indicated:

constexpr auto size() const requires *see below*;

-15- *Effects:* Equivalent to:

if constexpr (*is-integer-like*<W> && *is-integer-like*<Bound>) {
~~return (~~*value_* < 0)
? ((*bound_* < 0)
? *to-unsigned-like*(-*value_*) - *to-unsigned-like*(-*bound_*)
: *to-unsigned-like*(*bound_*) + *to-unsigned-like*(-*value_*))
: *to-unsigned-like*(*bound_*) - *to-unsigned-like*(*value_*);
using UC = *make-unsigned-like-t*<common_type_t<W, Bound>>;
return UC(*bound_*) - UC(*value_*);
} else
return *to-unsigned-like*(*bound_* - *value_*);

-16- *Remarks:* […]

**Option B:** Also fixes pathological cases involving unsigned-integer-like types

Modify 26.6.4.2 [range.iota.view] as indicated:

constexpr auto size() const requires *see below*;

-15- *Effects:* Equivalent to:

if constexpr (*is-integer-like*<W> && *is-integer-like*<Bound>) {
~~return (~~*value_* < 0)
? ((*bound_* < 0)
? *to-unsigned-like*(-*value_*) - *to-unsigned-like*(-*bound_*)
: *to-unsigned-like*(*bound_*) + *to-unsigned-like*(-*value_*))
: *to-unsigned-like*(*bound_*) - *to-unsigned-like*(*value_*);
using UC = *make-unsigned-like-t*<common_type_t<W, Bound>>;
if constexpr (*is-signed-integer-like*<W>)
return UC(*bound_*) - UC(*value_*);
else
return UC(W(UC(*bound_*) - UC(*value_*)));
} else
return *to-unsigned-like*(*bound_* - *value_*);

-16- *Remarks:* […]