size return end - begin?Section: 25.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 25.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.
Modify 25.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 formake-unsigned-likewhich is defined in [ranges.syn]/1, not in [range.subrange].]
-1- The name
sizedenotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::size(E)for some subexpressionEwith typeTis expression-equivalent to:
(1.1) —
decay-copy(extent_v<T>)ifTis an array type (6.9.4 [basic.compound]).
(1.2) — Otherwise, ifdisable_sized_range<remove_cv_t<T>>(25.4.4 [range.sized]) isfalse:(1.?
2.1) — Otherwise, ifdisable_sized_range<remove_cv_t<T>>(25.4.4 [range.sized]) isfalseanddecay-copy(E.size())if itis a valid expressionand its typeof integer-like type (24.3.4.4 [iterator.concept.winc]),Iisdecay-copy(E.size()).(1.?
2.2) — Otherwise, ifdisable_sized_range<remove_cv_t<T>>isfalseanddecay-copy(size(E))if itis a valid expressionand its typeof integer-like type with overload resolution performed in a context that includes the declaration:Iisand does not include a declaration oftemplate<class T>void size(Tauto&&) = delete;ranges::size,decay-copy(size(E)).
(1.3) — Otherwise, make-unsigned-like(ranges::end(E) - ranges::begin(E))
(25.5.4 [range.subrange]25.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> (24.3.4.8 [iterator.concept.sizedsentinel]) and
forward_iterator<I>. However, E is evaluated only once.
(1.4) — […]