viewable_range
mishandles lvalue move-only viewsSection: 25.4.5 [range.refinements] Status: C++23 Submitter: Casey Carter Opened: 2020-08-29 Last modified: 2023-11-22
Priority: 2
View all other issues in [range.refinements].
View all issues with C++23 status.
Discussion:
The viewable_range concept
(25.4.5 [range.refinements]) and the views:all
range adaptor (25.7.6 [range.all]) are duals: viewable_range
is intended to admit
exactly types T
for which views::all(declval<T>())
is well-formed. (Recall
that views::all(meow)
is a prvalue whose type models view
when it is
well-formed.) Before the addition of move-only view types to the design, this relationship was in
place (modulo an incredibly pathological case: a volatile
value of a view type with
volatile
-qualified begin
and end
models viewable_range
but is
rejected by views::all
unless it also has a volatile
-qualified copy constructor
and copy assignment operator). Adding move-only views to the design punches a bigger hole, however:
viewable_range
admits lvalues of move-only view types for which views::all
is
ill-formed because these lvalues cannot be decay-copied.
viewable_range
and views::all
so that instantiations of components constrained with viewable_range
(which often appears
indirectly as views::all_t<R>
in deduction guides) continue to be well-formed when
the constraints are satisfied.
[2020-09-06; Reflector prioritization]
Set priority to 2 during reflector discussions.
[2021-05-24; Reflector poll]
Set status to Tentatively Ready after five votes in favour during reflector poll.
[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4861.
Modify 25.4.5 [range.refinements] as indicated:
-5- The
viewable_range
concept specifies the requirements of arange
type that can be converted to aview
safely.template<class T> concept viewable_range = range<T> &&(borrowed_range<T> || view<remove_cvref_t<T>>);((view<remove_cvref_t<T>> && constructible_from<remove_cvref_t<T>, T>) || (!view<remove_cvref_t<T>> && borrowed_range<T>));