view_interface::back()
for sized random-access views| Document #: | D0000R0 Latest Status |
| Date: | 2026-05-06 |
| Project: | Programming Language C++ |
| Audience: |
SG9 Library Evolution Working Group Library Working Group |
| Reply-to: |
Daniel Pfeifer <daniel@pfeifer-mail.de> |
std::ranges::view_interface
provides
back() only
for views that model
bidirectional_range and
common_range. That is sufficient to
specify
back() as
*ranges::prev(ranges::end(r)),
but it is not the only case in which
back() can
be provided efficiently.
A view that models
random_access_range and
sized_range can also provide
back() in
constant time, even if it does not model
common_range. This paper extends
view_interface::back()
to that case.
[P3411R6] specifies that
any_view is never a
common_range. Consequently, under
the current specification strategy of
view_interface,
any_view can never provide
back().
The existing wording specifies
back()
as:
*ranges::prev(ranges::end(r))
That expression requires
common_range. For a
random_access_range that is also a
sized_range, the last element can
instead be expressed as:
ranges::begin(r)[ranges::size(r) - 1]
This paper adopts that formulation for
view_interface::back(),
making
back()
available for sized random-access specializations of
any_view and other sized
random-access views with distinct iterator and sentinel types.
Extend the constraints on the two
view_interface::back()
overloads to also permit
random_access_range && sized_range.
This does not change semantics for the existing common-bidirectional
case. It makes additional programs well-formed by enabling
back() for
sized random-access views whose iterator and sentinel types differ.
Existing valid calls to
view_interface::back()
retain their semantics. Expressions that are currently ill-formed become
well-formed for the newly supported category of views.
Code that explicitly checks whether a view has a
back()
member may therefore observe different results. That is the intended
effect.
The wording is relative to [N5054].
[ Editor's note: Modify the declarations of
back() in the synopsis as
follows: ]
constexpr decltype(auto) back() requires
(bidirectional_range<D> && common_range<D>) ||
(random_access_range<D> && sized_range<D>);
constexpr decltype(auto) back() const requires
(bidirectional_range<const D> && common_range<const D>) ||
(random_access_range<const D> && sized_range<const D>);[ Editor's note: Modify the declarations of
back() and paragraph 4 as
follows. Paragraph 3 is unchanged and shown for context. ]
constexpr decltype(auto) back() requires
(bidirectional_range<D> && common_range<D>) ||
(random_access_range<D> && sized_range<D>);
constexpr decltype(auto) back() const requires
(bidirectional_range<const D> && common_range<const D>) ||
(random_access_range<const D> && sized_range<const D>);3 Hardened preconditions:
!empty()
is true.
4 Effects: Equivalent to:
if constexpr (common_range<decltype(derived())>)
return *ranges::prev(ranges::end(derived()));
else
return ranges::begin(derived())[ranges::size(derived()) - 1];