在[range.lazy.split.view]中, ( P2210之前lazy_split_view
的原始C++20 )的概要定义如下:split_view
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();
// ...
};
与重新设计不同的是split_view
,它可以拆分input_range
。根据其约束,我们可以发现when V
is input_range
,Pattern
must model tiny-range
,其中tiny-range
定义如下:
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);
为了保证在编译时tiny-range
的大小小于等于,我们必须通过它的类型来获取大小,这也要求函数是函数。1
R
size()
R
constexpr
static
而且在标准中,确实有范围类型,tiny-range
例如empty_view
和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));
}
但在我看来,when V
is input_range
, std::array<int, 1>
,span<int, 1>
甚至int[1]
可以是有效Pattern
类型,因为我们也可以直接从类型中提取它们的大小,但是这三个都没有static size()
函数,导致无法建模tiny_range
。
另外,由于存在以下CTAD:
template<class R, class P>
lazy_split_view(R&&, P&&) -> lazy_split_view<views::all_t<R>, views::all_t<P>>;
当V
是时input_range
,Pattern
永远不能是非view
范围,因为views::all_t
会产生ref_view
or owning_view
,这两者都不是tiny-range
甚至Pattern
它自己都可以建模tiny-range
(天螺栓):
#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
}
总之, 的定义tiny-range
似乎将范围的类型限制Pattern
为一个非常小的集合 when V
is an input_range
。标准中这样限制的原因是什么?