C++ Logo


Advanced search

Re: ranges::set_intersection and ranges::set_difference requirements are too strict

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Wed, 10 Mar 2021 11:19:35 -0500
On Wed, Mar 10, 2021 at 10:36 AM Alexander Bessonov via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> I thought STL was about the reuse of algorithms: "that's a rotate!",
> remember? :)
> What makes me sad is that set algorithms being promoted to
> "ranges"-version
> became more strict than their original "std" variants.

Yes. An uncharitable way of saying this would be: Don't think of
std::ranges as "Classic STL v2"; think of it as "Range-v3, License-Free
Edition." It's not intended to be as generic (or as concerned with
compile-time efficiency) as the original STL; it's supposed to be
specifically Eric Niebler's Range-v3 library but usable by people at
companies that don't permit them to use random libraries off GitHub.

BTW, the same is with sort/is_sorted:
> // legacy code
> bool operator<(const A &a1, const A &a2) { ... }
> std::vector<A> c;
> std::sort(c.begin(), c.end());
> The last line being changed to
> std::ranges::sort(c);
> does not compile anymore. ranges::less is also unnecessary strict (in this
> case), but at least you can pass a std::less{} instead.

Yeah, but at least here std::ranges is enforcing good style. I always say
that types shouldn't provide `<` without `>` (nor `==` without `!=`,
although that advice becomes more complicated in C++20 because `!=` is
sometimes synthesized).
If your type wants to provide a "less-than predicate" without the matching
"greater-than predicate," it should expose something like
struct A::Less {
    bool operator()(const A&, const A&) const;
instead. This correctly connotes "here's a predicate you can use in
standard algorithms" without incorrectly connoting "instances of A are
*comparable* in the ordinary mathematical sense."

Ranges basically forces you to "opt in" in this case by passing a
predicate. In my preferred good code you'd say
    std::sort(c.begin(), c.end(), A::Less{}); // or equivalently,
    std::ranges::sort(c.begin(), c.end(), A::Less{});
so it's kind of a cop-out that the standard library allows you to say
    std::ranges::sort(c.begin(), c.end(), std::less{});
which means you can continue to get away with providing `<`-without-`>`.

my $.02,

Received on 2021-03-10 10:19:48