3

In [range.lazy.split.view], the synopsis of lazy_split_view (the original C++20 split_view before P2210) is defined as follows:

template<input_­range V, forward_­range Pattern>
    requires view<V> && view<Pattern> &&                
             (forward_­range<V> || tiny-range<Pattern>)
class lazy_split_view : public view_interface<lazy_split_view<V, Pattern>> {
private:
  V base_ = V();
  Pattern pattern_ = Pattern();
  // ...
};

Unlike the redesigned split_view, it can split input_range. According to its constraints, we can find that when V is input_range, the Pattern must model tiny-range, where tiny-range is defined as follows:

template<auto> struct require-constant;

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

In order to ensure that the size of tiny-range is less than or equal to 1 at compile-time, we must obtain the size of R through its type, which also requires the size() function of R to be a constexpr static function.

And in the standard, there are indeed range type that model tiny-range such as empty_view and single_view (godbolt):

#include <ranges>
#include <sstream>

int main() {
  auto ints = std::istringstream{"42"};
  auto r = std::ranges::istream_view<int>(ints);
  auto s1 = r | std::views::lazy_split(std::views::empty<int>);
  auto s2 = r | std::views::lazy_split(std::views::single(0));
}

But in my opinion, when V is input_range, std::array<int, 1>, span<int, 1> or even int[1] can be valid Pattern types, because we can also directly extract their size from the type, but none of the three have a static size() function, which makes them unable to model tiny_range.

In addition, because of the existence of the following CTAD:

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

When V is an input_range, the Pattern can never be a non-view range, because views::all_t will produce ref_view or owning_view, neither of which is tiny-range even Pattern itself may model tiny-range (godbolt):

#include <ranges>
#include <stream>
#include <array>

int main() {
  auto ints = std::istringstream{"42"};
  auto r = std::ranges::istream_view<int>(ints);
  std::array p{42};
  r | std::views::lazy_split(p);  // ref_view<array<int, 1>> is not tiny-range 
  r | std::views::lazy_split(std::span{p}); // span<int, 1>> is not tiny-range
}

In summary, the definition of tiny-range seems to limit the type of Pattern range to a very small set when V is an input_range. What is the reason for such restriction in the standard?

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • C++20 has no `lazy_split_view`. – Nicol Bolas Dec 26 '21 at 19:11
  • @NicolBolas `lazy_split_view` comes from [P2210](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2210r2.html) which is a C++20 DR (not a C++23 proposal), that is to say, after P2210 is implemented, `-std=c++20` *can* guarantee `lazy_split_view`. Why do you say that it does not come from C++20? – 康桓瑋 Dec 26 '21 at 19:14

0 Answers0