This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3474. Nesting `join_view`s is broken because of CTAD

Section: 26.7.14 [range.join] Status: WP Submitter: Barry Revzin Opened: 2020-08-04 Last modified: 2020-11-09

Priority: Not Prioritized

View all other issues in [range.join].

View all issues with WP 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 (26.7.2 [range.adaptor.object]). Given a subexpression `E`, the expression `views::join(E)` is expression-equivalent to `join_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 26.7.14.1 [range.join.overview] p2

> The name `views::join` denotes a range adaptor object (26.7.2 [range.adaptor.object]). Given a subexpression `E`, the expression `views::join(E)` is expression-equivalent to `join_view<views::all_t<decltype((E))>>{E}`.

Or in code (Option B) add a deduction guide to 26.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:

> 1. Modify 26.7.14.1 [range.join.overview] as indicated:

>    > -2- `The name views::join` denotes a range adaptor object (26.7.2 [range.adaptor.object]). Given a subexpression `E`, the expression `views::join(E)` is expression-equivalent to `join_view<views::all_t<decltype((E))>>{E}`.

> Option B:

> 1. Modify 26.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.

1. Modify 26.7.14.1 [range.join.overview] as indicated:

   > -2- `The name views::join` denotes a range adaptor object (26.7.2 [range.adaptor.object]). Given a subexpression `E`, the expression `views::join(E)` is expression-equivalent to `join_view<views::all_t<decltype((E))>>{E}`.