lazy_split_view, CTAD doesn't work when given an input_range input and a tiny-range patternSection: 25.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 (25.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:
// AssumingInputRangeandTinyRangeare 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 (25.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.
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 25.7.16.2 [range.lazy.split.view] to 25.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.
Modify 25.5.2 [range.utility.helpers] as indicated:
[Drafting note: This change effectively just moves the definitions of
require-constantandtiny-rangefrom 25.7.16.2 [range.lazy.split.view] to 25.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);
Modify 25.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_); }
[…]
Modify 25.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-constantandtiny-rangefrom 25.7.16.2 [range.lazy.split.view] to 25.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>> {
[…]
};
[…]
}