Theme

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
<>

1 Abstract

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.

2 Motivation

[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.

3 Proposal

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.

4 Impact on existing code

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.

5 Wording

The wording is relative to [N5054].

25.5.3.1 General [view.interface.general]

[ 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>);

25.5.3.2 Members [view.interface.members]

[ 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];

6 References

[N5054] Thomas Köppe. 2026-07-16. Working Draft, Programming Languages — C++.
https://wg21.link/n5054
[P3411R6] Hui Xie, S. Levent Yilmaz, Louis Dionne, Patrick Roberts. 2026-05-09. `any_view`.
https://wg21.link/p3411r6