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.

### 3563. `keys_view` example is broken

Section: 26.7.22.1 [range.elements.overview] Status: WP Submitter: Barry Revzin Opened: 2021-05-29 Last modified: 2021-10-14

Priority: 3

View all issues with WP status.

Discussion:

In 26.7.22.1 [range.elements.overview] we have:

> `keys_view` is an alias for `elements_view<views::all_t<R>, 0>`, and is useful for extracting keys from associative containers.

> [Example 2:

> >     auto names = keys_view{historical_figures};
> >     for (auto&& name : names) {
> >       cout << name << ' ';  // prints Babbage Hamilton Lovelace Turing
> >     }

> — end example]

Where `keys_view` is defined as:

>     template<class R>
>       using keys_view = elements_view<views::all_t<R>, 0>;

There's a similar example for `values_view`.

But class template argument deduction cannot work here, `keys_view(r)` cannot deduce `R` — it's a non-deduced context. At the very least, the example is wrong and should be rewritten as `views::keys(historical_figures)`. Or, I guess, as `keys_view<decltype(historical_figures)>(historical_figures)>` (but really, not).

[2021-05-29 Tim comments and provides wording]

I have some ideas about making CTAD work for `keys_view` and `values_view`, but current implementations of alias template CTAD are not yet in a shape to permit those ideas to be tested. What is clear, though, is that the current definitions of `keys_view` and `values_view` can't possibly ever work for CTAD, because `R` is only used in a non-deduced context and so they can never meet the "deducible" constraint in 12.2.2.9 [over.match.class.deduct] p2.3.

The proposed resolution below removes the `views::all_t` transformation in those alias templates. This makes these aliases transparent enough to support CTAD out of the box when a view is used, and any questions about deduction guides on `elements_view` can be addressed later once the implementations become more mature. This also makes them consistent with all the other views: you can't write `elements_view<map<int, int>&, 0>` or `reverse_view<map<int, int>&>`, so why do we allow `keys_view<map<int, int>&>`? It is, however, a breaking change, so it is important that we get this in sooner rather than later.

The proposed resolution has been implemented and tested.

[2021-06-14; Reflector poll]

Set priority to 3 after reflector poll in August. Partially addressed by an editorial change.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4885.

> 1. Modify 26.2 [ranges.syn], header `<ranges>` synopsis, as indicated:

>    >     […]
>    >     namespace std::ranges {
>    >     […]

>    >       // 26.7.22 [range.elements], elements view
>    >       template<input_range V, size_t N>
>    >         requires see below
>    >       class elements_view;

>    >       template<class T, size_t N>
>    >         inline constexpr bool enable_borrowed_range<elements_view<T, N>> = enable_borrowed_range<T>;

>    >       template<class R>
>    >         using keys_view = elements_view<views::all_t<R>, 0>;
>    >       template<class R>
>    >         using values_view = elements_view<views::all_t<R>, 1>;

>    >     […]
>    >     }

> 2. Modify 26.7.22.1 [range.elements.overview] as indicated:

>    > -3- `keys_view` is an alias for `elements_view<views::all_t<R>, 0>`, and is useful for extracting keys from associative containers.

>    > [Example 2:

>    > >     auto names = keys_view{views::all(historical_figures)};
>    > >     for (auto&& name : names) {
>    > >       cout << name << ' '; // prints Babbage Hamilton Lovelace Turing
>    > >     }

>    > — end example]

>    > -4- `values_view` is an alias for `elements_view<views::all_t<R>, 1>`, and is useful for extracting values from associative containers.

>    > [Example 3:

>    > >     auto is_even = [](const auto x) { return x % 2 == 0; };
>    > >     cout << ranges::count_if(values_view{views::all(historical_figures)}, is_even); // prints 2

>    > — end example]

[2021-06-18 Tim syncs wording to latest working draft]

The examples have been editorially corrected, so the new wording simply changes the definition of `keys_view` and `values_view`.

[2021-09-20; Reflector poll]

Set status to Tentatively Ready after six votes in favour during reflector poll.

[2021-10-14 Approved at October 2021 virtual plenary. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4892.

1. Modify 26.2 [ranges.syn], header `<ranges>` synopsis, as indicated:

   >     […]
   >     namespace std::ranges {
   >     […]

   >       // 26.7.22 [range.elements], elements view
   >       template<input_range V, size_t N>
   >         requires see below
   >       class elements_view;

   >       template<class T, size_t N>
   >         inline constexpr bool enable_borrowed_range<elements_view<T, N>> = enable_borrowed_range<T>;

   >       template<class R>
   >         using keys_view = elements_view<views::all_t<R>, 0>;
   >       template<class R>
   >         using values_view = elements_view<views::all_t<R>, 1>;

   >     […]
   >     }

2. Modify 26.7.22.1 [range.elements.overview] as indicated:

   > -3- `keys_view` is an alias for `elements_view<views::all_t<R>, 0>`, and is useful for extracting keys from associative containers.

   > [Example 2: … — end example]

   > -4- `values_view` is an alias for `elements_view<views::all_t<R>, 1>`, and is useful for extracting values from associative containers.

   > [Example 3: … — end example]