C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Bool casting operator to check if a container not empty

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Thu, 2 Nov 2023 11:58:50 -0400
Ville, I think you've temporarily forgotten the mess that is
`optional<bool>`.
"Empty" (as in "it's a range of zero elements, i.e. its value is the empty
sequence") and "disengaged" (as in "it has no value") are two different
concepts; and both are fundamentally different from "falsey" (as in "its
value is boolean false").
Implicit conversions are the root of much evil in C++.

On Thu, Nov 2, 2023 at 11:10 AM Ville Voutilainen via Std-Proposals <
std-proposals_at_[hidden]> wrote:

>
> A call to an overload set that deals with ranges or singular values. Thus:
>
> template<class T, class F> void checked_process_it(T&& t)
> {
> if (t)
> process_it(std::forward<T>(t));
> else
> nag("hey, don't do that");
> }
>

I think what the programmer meant here was more like:
    if constexpr (!std::ranges::range<T>) {
        process_it(std::views::single(std::forward<T>(t)));
    } else {
        process_it(t);
    }
Obviously if `process_it` expects a ranges::range, it has to be prepared to
deal with the possibility that the range is empty (even if the way it deals
with that is just to say `if (ranges::empty(rg)) nag()`), since ranges *can*
be empty.
    checked_process_it(std::vector<int>{}); // original code nags
    checked_process_it(std::make_optional(std::vector<int>{})); //
original code fails to nag
Furthermore, if `checked_process_it` really intends to deal with optionals,
(smart) pointers, etc., then it is probably missing some code to unwrap the
optional/pointer after checking it for engagement/non-nullness. That is,
instead of
    if (t)
      process_it(t);
the programmer probably meant
    if (t.has_value())
      process_it(t.value()); // not just `t`!
and/or
    if (t != nullptr)
      process_it(*t); // not just `t`!


I can put it into a refined range concept that has the ability to
> check emptiness, though.
> And this really sounds like a bug in ranges that could be entertained
> to be fixed retroactively,
> even if that causes a little breakage. It's quite odd if a generic
> view that can be as lazy as imaginable
> can provide an empty() but a generic range can't.
>

FYI, some input ranges can't provide .empty().
The C++20 Ranges library solution is to provide a* free function* (well,
CPO) `ranges::empty` and tell people to use it instead. Ranges provides all
these "generic" primitive functions through CPOs instead of member
functions; that's just its style, for better and worse.

–Arthur

Received on 2023-11-02 15:59:05