C++ Logo

std-proposals

Advanced search

Re: [std-proposals] <ranges>: Provide member empty() for ranges adaptors (whenever possible)

From: Hewill Kang <hewillk_at_[hidden]>
Date: Wed, 31 Jan 2024 01:56:23 +0800
Sorry about split_view::empty(), my understanding is not quite right.
It seems that the synthesized empty() should return true when the split
range and pattern range are both empty.


Hewill Kang <hewillk_at_[hidden]> 於 2024年1月31日 週三 上午1:48寫道:

> But in this case my intuition was correct: `ranges::empty(r)` doesn't
>> require `r` to be forward_range or sized_range. It correctly works on
>> anything with a `.empty()` member.
>
>
> Exactly, but that's where I think there's an issue with the standards.
> If ranges::empty(r) calls (ranges::size(r) == 0) or ranges::begin(r) ==
> ranges::end(r), then its return value is meaningful because it indicates
> whether the range is empty, given that sized_range requires ranges::size() to
> be equal to ranges::distance().
> When ranges::empty(r) ultimately results in calling a range's empty() memebr (if
> it exists), what is the meaning of the value returned by its member
> empty()?
> I don't see *anything* stating this in the standard, which means the
> standard doesn't necessarily require that it returns the number of elements
> in the range.
> It is possible that the behavior of empty() is to clear all contents of
> the range and return true if the clearing is successful, just like clear(),
> which is what [[nodiscard]] is used to detect the API name that is
> considered to be “not quite right API name”.
> Also, the standard does not specify the time complexity of ranges::empty(),
> which means that unlike rangs::size() when sized_range is satisfied, it
> does *not* guarantee a constant time complexity.
> This is why I want to introduce concepts such as *empty-checkable-range* to
> clarify the above confusion.
>
> So the proposal is to make sure that every Ranges view type with a
>> `.size()` also has a `.empty()`, is that correct (now)?
>
>
> The proposal is to provide empty() members for *input* range adapters
> whenever possible. (there is no need to provide empty() for forward range
> adaptors because view_interface can always synthesize it).
> Given that checking whether adaptors are empty is simpler than calculating
> their size, this proposal observes whether the underlying range can be
> applied to ranges::empty() to synthesize the empty() member (with the
> *corresponding formula* with ranges::empty(*base_*)) for the adaptors.
> The inference of such a formula also results in some adaptors that do not
> have a .size() member can have .empty(), such as split_view, which is
> always non-empty (if LWG 4017 <https://cplusplus.github.io/LWG/issue4017>
> is adopted), so it can provide an empty() that always returns false.
> Hope that clarifies your question.
>
> Hewill
>
>
> Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]> 於 2024年1月31日 週三 上午1:14寫道:
>
>> On Tue, Jan 30, 2024 at 11:45 AM Hewill Kang <hewillk_at_[hidden]> wrote:
>>
>>> I support the general direction of making the Ranges view types more
>>>> consistent; but why is your proposal not simply to change
>>>> https://eel.is/c++draft/view.interface
>>>> like this?
>>>
>>>
>>> I believe this does not solve the original issue.
>>> Let’s leave aside the issue of constraints relying on themselves this
>>> may cause.
>>>
>>
>> `ranges::empty(derived())` is not the same thing as
>> `ranges::empty(*this)`... oh, I see, I meant the equivalent of
>> `ranges::empty(*base()*)` — that is, if the *actual thing* provides
>> `empty()` then we should use that. But view_interface is CRTP — not an
>> adaptor *over* the actual thing but a substrate *contributing to* the
>> actual thing. My suggestion doesn't apply, then.
>>
>>
>>
>>> In my original example, the type of s | std::views::as_rvalue is as_rvalue_view<subrange<istream_iterator<int>,
>>> istream_iterator<int>>>, so derived() returns as_rvalue_view, and
>>> ranges::empty cannot be applied to this as_rvalue_view since it is
>>> neither forward_range nor sized_range.
>>>
>>
>> But in this case my intuition was correct: `ranges::empty(r)` doesn't
>> require `r` to be forward_range or sized_range. It correctly works on
>> anything with a `.empty()` member.
>> https://eel.is/c++draft/range.prim.empty
>>
>> So the proposal is to make sure that every Ranges view type with a
>> `.size()` also has a `.empty()`, is that correct (now)?
>> And the only viable way to do that is to add the `.empty()` method to the
>> specification of each individual view (take_view, drop_view, etc.), just
>> like we already do for `.size()` today?
>>
>> –Arthur
>>
>

Received on 2024-01-30 17:56:35