This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++23 status.
join_view
s is broken because of CTADSection: 25.7.14 [range.join] Status: C++23 Submitter: Barry Revzin Opened: 2020-08-04 Last modified: 2023-11-22
Priority: Not Prioritized
View all other issues in [range.join].
View all issues with C++23 status.
Discussion:
Let's say I had a range of range of ranges and I wanted to recursively flatten it. That would involve
repeated invocations of join
. But this doesn't work:
std::vector<std::vector<std::vector<int>>> nested_vectors = { {{1, 2, 3}, {4, 5}, {6}}, {{7}, {8, 9}, {10, 11, 12}}, {{13}} }; auto joined = nested_vectors | std::views::join | std::views::join;
The expectation here is that the value_type
of joined is int
, but it's actually
vector<int>
— because the 2nd invocation of join
ends up just copying
the first. This is because join
is specified to do:
The name
views::join
denotes a range adaptor object (25.7.2 [range.adaptor.object]). Given a subexpressionE
, the expressionviews::join(E)
is expression-equivalent tojoin_view{E}
.
And join_view{E}
for an E
that's already a specialization of a join_view
just gives you the same join_view
back. Yay CTAD. We need to do the same thing with join
that we did with reverse
in P1252. We can do that either in
exposition (Option A) my modifying 25.7.14.1 [range.join.overview] p2
The name
views::join
denotes a range adaptor object (25.7.2 [range.adaptor.object]). Given a subexpressionE
, the expressionviews::join(E)
is expression-equivalent tojoin_view<views::all_t<decltype((E))>>{E}
.
Or in code (Option B) add a deduction guide to 25.7.14.2 [range.join.view]:
template<class R> explicit join_view(R&&) -> join_view<views::all_t<R>>; template<class V> explicit join_view(join_view<V>) -> join_view<join_view<V>>;
[2020-08-21; Issue processing telecon: Option A is Tentatively Ready]
Previous resolution [SUPERSEDED]:
This wording is relative to N4861.
[Drafting Note: Two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]
Option A:
Modify 25.7.14.1 [range.join.overview] as indicated:
-2-
The name views::join
denotes a range adaptor object (25.7.2 [range.adaptor.object]). Given a subexpressionE
, the expressionviews::join(E)
is expression-equivalent tojoin_view<views::all_t<decltype((E))>>{E}
.Option B:
Modify 25.7.14.2 [range.join.view] as indicated:
namespace std::ranges { […] template<class R> explicit join_view(R&&) -> join_view<views::all_t<R>>; template<class V> explicit join_view(join_view<V>) -> join_view<join_view<V>>; }
[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]
Proposed resolution:
This wording is relative to N4861.
Modify 25.7.14.1 [range.join.overview] as indicated:
-2-
The name views::join
denotes a range adaptor object (25.7.2 [range.adaptor.object]). Given a subexpressionE
, the expressionviews::join(E)
is expression-equivalent tojoin_view<views::all_t<decltype((E))>>{E}
.