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.
tiny-range
is not quite rightSection: 25.7.16.2 [range.lazy.split.view] Status: New Submitter: Hewill Kang Opened: 2023-01-07 Last modified: 2025-04-28
Priority: 4
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:
Currently, lazy_split_view
supports input range when the element of the pattern is less than or equal to 1.
In order to ensure this condition at compile time, tiny-range
constrains the type R
to model
sized_range
and requires (remove_reference_t<R>::size() <= 1)
to be a constant expression.
sized_range
does not guarantee that ranges::size
will be evaluated by R::size()
.
For example, when disable_sized_range<R>
is specialized to true
or R::size()
returns a non-integer-like type,
ranges::size
can still compute the size by subtracting the iterator-sentinel pair when both satisfy sized_sentinel_for
.
Since the lazy_split_view
's iterator uses R::size()
to get the constant value of the pattern,
we must ensure that this is indeed how ranges::size
is calculated. Also, I think we can simplify
tiny-range
with bool_constant
in a way similar to LWG 3150(i), which removes the
introduction of require-constant
.
[2023-02-01; Reflector poll]
Set priority to 4 after reflector poll.
Only matters for pathological types.
Maybe use requires bool_constant<ranges::size(r) <= 1>
.
Previous resolution [SUPERSEDED]:
This wording is relative to N4917.
Modify 25.7.16.2 [range.lazy.split.view] as indicated:
namespace std::ranges {template<auto> struct require-constant; // exposition onlytemplate<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>> { […] }; […] }template<class R> concept tiny-range = // exposition only sized_range<R> && requires { requires bool_constant<(remove_reference_t<R>::size() <= 1)>::value; };-?- Given an lvalue
r
of typeremove_reference_t<R>
,R
modelstiny-range
only ifranges::size(r)
is evaluated byremove_reference_t<R>::size()
.constexpr lazy_split_view(V base, Pattern pattern);-1- Effects: : Initializes
base_
withstd::move(base)
, andpattern_
withstd::move(pattern)
.
[2025-04-27, Hewill provides alternative wording]
Proposed resolution:
This wording is relative to N5008.
Modify 25.7.16.2 [range.lazy.split.view] as indicated:
[Drafting note: This benefits from P2280 that a call to a member function of a non-constexpr object can be a constant expression if it does not actually access the member.
This would makeviews::lazy_split(r, span<int, 0>{})
well-formed, which can be seen as an enhancement.]
namespace std::ranges {template<auto> struct require-constant; // exposition onlytemplate<class R> concept tiny-range = // exposition only sized_range<R> && requires (R& r) { requires bool_constant<ranges::size(r) <= 1>::value; }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::view_interface<lazy_split_view<V, Pattern>> { […] }; […] }
Modify 25.7.16.5 [range.lazy.split.inner] as indicated:
[Drafting note: We can't use
if constexpr (ranges::size(i_.parent_->pattern_) == 0)
here because it is not a constant expression, and it seems more intuitive to just useranges::empty
combined with runtimeif
which is always well-formed. Note that the PR does not seek the aggressive optimization that minimizes the instantiation as this is not the intent of the current design (for example,outer-iterator& operator++()
can be specialized for the case wherePattern::size() == 0
to save some O(1) comparisons), library implementations are free to optimize as it pleases.]
constexpr inner-iterator& operator++();-5- Effects: Equivalent to:
incremented_ = true; if constexpr (!forward_range<Base>) { if (ranges::empty(i_.parent_->pattern_))if constexpr (Pattern::size() == 0) {return *this; } } ++i_.current; return *this;