This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
concat_view rejects non-movable referencesSection: 25.7.18.2 [range.concat.view] Status: New Submitter: Hewill Kang Opened: 2024-05-01 Last modified: 2024-06-24
Priority: 4
View other active issues in [range.concat.view].
View all other issues in [range.concat.view].
View all issues with New status.
Discussion:
In order to prevent non-equality-preserving behavior of operator* and iter_move,
concat_view introduces the concat-indirectly-readable concept, part of which is:
template<class Ref, class RRef, class It>
concept concat-indirectly-readable-impl = // exposition only
requires (const It it) {
{ *it } -> convertible_to<Ref>;
{ ranges::iter_move(it) } -> convertible_to<RRef>;
};
This isn't quite right because convertible_to checks is_convertible_v which doesn't
understand copy elision. This makes the current concat_view unable to work with ranges whose
reference is non-movable prvalue:
auto r = std::views::iota(0, 5)
| std::views::transform([](int) { return NonMovable{}; });
auto c1 = std::ranges::concat_view(r); // ill-formed, concat_indirectly_readable not satisfied
auto c2 = std::ranges::concat_view(r, r); // ditto
Since std::visit<R> is used in the implementation to perform reference conversion for the
underlying iterator, the more accurate one should be is_invocable_r which does understand guaranteed
elision.
join_with_view has the same issue because compatible-joinable-ranges
requires that the value_type of the inner range and pattern range must satisfy common_with,
which always fails for non-movable types. However, this can be automatically resolved by LWG
4074(i)'s resolution.
[2024-06-24; Reflector poll]
Set priority to 4 after reflector poll. "Proposed resolution loses the existing requirement that the conversion is equality-preserving." "Don't care about rejecting non-movable reference types."
Proposed resolution:
This wording is relative to N4981.
Modify 25.7.18.2 [range.concat.view] as indicated:
-1- The exposition-only
concat-indirectly-readableconcept is equivalent to:template<class Ref, class CRef> concept concat-ref-compatible-with = is_invocable_r_v<CRef, Ref()>; // exposition only template<class Ref, class RRef, class It> concept concat-indirectly-readable-impl = // exposition only requires (const It it) { { *it } ->convertible_toconcat-ref-compatible-with<Ref>; { ranges::iter_move(it) } ->convertible_toconcat-ref-compatible-with<RRef>; }; template<class... Rs> concept concat-indirectly-readable = // exposition only common_reference_with<concat-reference-t<Rs...>&&, concat-value-t<Rs...>&> && common_reference_with<concat-reference-t<Rs...>&&, concat-rvalue-reference-t<Rs...>&&> && common_reference_with<concat-rvalue-reference-t<Rs...>&&, concat-value-t<Rs...> const&> && (concat-indirectly-readable-impl<concat-reference-t<Rs...>, concat-rvalue-reference-t<Rs...>, iterator_t<Rs>> && ...);