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

### 3368. Exactly when does `size` return `end - begin`?

Section: 26.3.10 [range.prim.size] Status: Resolved Submitter: Casey Carter Opened: 2020-01-07 Last modified: 2021-02-25

Priority: 0

View all issues with Resolved status.

Discussion:

The specification of `ranges::size` in 26.3.10 [range.prim.size] suggests that bullet 1.3 ("Otherwise, `make-unsigned-like(ranges::end(E) - ranges::begin(E)) ...")` only applies when `disable_sized_range<remove_cv_t<T>>` is `true`. This is not the design intent, but the result of an erroneous attempt to factor out the common "`disable_sized_range` is `false`" requirement from the member and non-member `size` cases in bullets 1.2.1 and 1.2.2 that occurred between P0896R3 and P0896R4. The intended design has always been that a range with member or non-member `size` with the same syntax but different semantics may opt-out of being sized by specializing `disable_sized_range`. It has never been intended that arrays or ranges whose iterator and sentinel model `sized_sentinel_for` be able to opt out of being sized via `disable_sized_range`. `disable_sized_sentinel_for` can/must be used to opt out in the latter case so that library functions oblivious to the range type that operate on the iterator and sentinel of such a range will avoid subtraction.

[2020-01-25 Status set to Tentatively Ready after six positive votes on the reflector.]

[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]

[2020-11-18 This was actually resolved by P2091R0 in Prague. Status changed: WP → Resolved.]

Proposed resolution:

This wording is relative to N4842.

1. Modify 26.3.10 [range.prim.size] as indicated:

   > [Drafting note: There are drive-by changes here to (1) avoid introducing unused type placeholders, (2) avoid reusing "`T`" as both the type of the subexpression and the template parameter of the poison pill, and (3) fix the cross-reference for `make-unsigned-like` which is defined in [ranges.syn]/1, not in [range.subrange].]

   > -1- The name `size` denotes a customization point object (16.3.3.3.6 [customization.point.object]). The expression `ranges::size(E)` for some subexpression `E` with type `T` is expression-equivalent to:

   > 1. (1.1) — `decay-copy(extent_v<T>)` if `T` is an array type (6.8.4 [basic.compound]).

   > 2. (1.2) — Otherwise, if `disable_sized_range<remove_cv_t<T>>` (26.4.3 [range.sized]) is `false`:

   > 3. (1.?2.1) — Otherwise, if `disable_sized_range<remove_cv_t<T>>` (26.4.3 [range.sized]) is `false` and `decay-copy(E.size())` if it is a valid expression and its type `I` is of integer-like type (25.3.4.4 [iterator.concept.winc]), `decay-copy(E.size())`.

   > 4. (1.?2.2) — Otherwise, if `disable_sized_range<remove_cv_t<T>>` is `false` and `decay-copy(size(E))` if it is a valid expression and its type `I` is of integer-like type with overload resolution performed in a context that includes the declaration:

   >    >     template<class T> void size(Tauto&&) = delete;

   >    and does not include a declaration of `ranges::size`, `decay-copy(size(E))`.

2. (1.3) — Otherwise, `make-unsigned-like(ranges::end(E) - ranges::begin(E))` (26.5.4 [range.subrange]26.2 [ranges.syn]) if it is a valid expression and the types `I` and `S` of `ranges::begin(E)` and `ranges::end(E)` (respectively) model both `sized_sentinel_for<S, I>` (25.3.4.8 [iterator.concept.sizedsentinel]) and `forward_iterator<I>`. However, `E` is evaluated only once.

3. (1.4) — […]