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.

### 3685. In `lazy_split_view`, CTAD doesn't work when given an `input_range` input and a `tiny-range` pattern

Section: 26.7.16.2 [range.lazy.split.view] Status: New Submitter: Konstantin Varlamov Opened: 2022-03-23 Last modified: 2022-05-17

Priority: 3

View other active issues in [range.lazy.split.view].

View all other issues in [range.lazy.split.view].

View all issues with New status.

Discussion:

In `lazy_split_view`, the deduction guide that accepts two arbitrary types wraps the arguments in `views::all_t` (26.7.16.2 [range.lazy.split.view]):

>     template<class R, class P>
>       lazy_split_view(R&&, P&&) -> lazy_split_view<views::all_t<R>, views::all_t<P>>;

When trying to use an `input_range` as the input, `lazy_split_view` requires the pattern type to satisfy the exposition-only concept `tiny-range`. Trying to use CTAD with an `input_range` and a `tiny-range` as arguments results in a compiler error, as demonstrated in the demo link:

>     // Assuming `InputRange` and `TinyRange` are valid types satisfying the
>     // corresponding concepts.
>     std::ranges::lazy_split_view view{InputRange(), TinyRange()}; // Compiler error

The underlying reason is that `tiny-range` requires the given type to contain a static member function `size()` that returns a number `<=1` (26.7.16.2 [range.lazy.split.view]):

>     template<class R>
>       concept tiny-range =                                          // exposition only
>         sized_range<R> &&
>         requires { typename require-constant<remove_reference_t<R>::size()>; } &&
>         (remove_reference_t<R>::size() <= 1);

However, when given a range, `views::all_t` wraps the type in a `ranges::owning_view`. `owning_view` doesn't satisfy `tiny-range` for any template parameter because it never contains the static `size()` function required by the concept.

A general resolution might be modifying `owning_view` so that it satisfies `tiny-range` when the given type is a `tiny-range` (that would require moving the `tiny-range` concept from 26.7.16.2 [range.lazy.split.view] to 26.5.2 [range.utility.helpers]). A more localized solution can be to change the deduction guide in `lazy_split_view` to avoid wrapping a type satisfying `tiny-range` in `views::all_t`.

[2022-05-17; Reflector poll]

Set priority to 3 after reflector poll. One vote for NAD.

Proposed resolution:

This wording is relative to N4910.

1. Modify 26.5.2 [range.utility.helpers] as indicated:

   > [Drafting note: This change effectively just moves the definitions of `require-constant` and `tiny-range` from 26.7.16.2 [range.lazy.split.view] to 26.5.2 [range.utility.helpers].]

   >     […]
   >     template<class T, class U>
   >       concept different-from = // exposition only
   >         !same_as<remove_cvref_t<T>, remove_cvref_t<U>>;

   >     template<auto> struct require-constant; // exposition only

   >     template<class R>
   >     concept tiny-range = // exposition only
   >       sized_range<R> &&
   >       requires { typename require-constant<remove_reference_t<R>::size()>; } &&
   >       (remove_reference_t<R>::size() <= 1);

2. Modify 26.7.6.3 [range.owning.view], class template `owning_view` synopsis, as indicated:

   >     […]
   >     constexpr static auto size() requires tiny-range<R>
   >     { return R::size(); }
   >     constexpr auto size() requires sized_range<R>
   >     { return ranges::size(r_); }
   >     constexpr auto size() const requires sized_range<const R>
   >     { return ranges::size(r_); }
   >     […]

3. Modify 26.7.16.2 [range.lazy.split.view], class template `lazy_split_view` synopsis, as indicated:

   > [Drafting note: This change effectively just moves the definitions of `require-constant` and `tiny-range` from 26.7.16.2 [range.lazy.split.view] to 26.5.2 [range.utility.helpers].]

   >     namespace std::ranges {
   >       template<auto> struct require-constant; // exposition only

   >       template<class R>
   >       concept tiny-range = // exposition only
   >         sized_range<R> &&
   >         requires { typename require-constant<remove_reference_t<R>::size()>; } &&
   >         (remove_reference_t<R>::size() <= 1);

   >       template<input_range V, forward_range Pattern>
   >         requires view<V> && view<Pattern> &&
   >                  indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
   >                  (forward_range<V> || tiny-range<Pattern>)
   >       class lazy_split_view : public view_interface<lazy_split_view<V, Pattern>> {
   >         […]
   >       };
   >       […]
   >     }