C++ Logo


Advanced search

Re: [std-proposals] Addition of std::contains to Simplify Container Value Checks

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Sun, 24 Dec 2023 15:41:15 -0500
On Sun, Dec 24, 2023 at 12:25 PM Giuseppe D'Angelo via Std-Proposals
<std-proposals_at_[hidden]> wrote:
> Il 24/12/23 14:50, Ville Voutilainen via Std-Proposals ha scritto:
> > On Sun, 24 Dec 2023 at 15:44, Bjorn Reese via Std-Proposals
> > <std-proposals_at_[hidden]> wrote:
> >>
> >> On 12/23/23 10:20, Robert Sitton via Std-Proposals wrote:
> >>
> >>> Function Signature:
> >>> template <typename Container, typename T>
> >>> bool std::contains(const Container& container, const T& value);
> >>
> >> Why does it deviate from all other standard algorithms that takes
> >> iterators (or ranges for std::ranges algorithms)?
> >
> > Because it doesn't operate on iterators. If you pass a std::map to it,
> > it'll call std::map::contains,
> > it doesn't perform a silly linear walk from one iterator to another.
> > What we're looking at here is basically
> > "call the argument's contains() if available, do a ranges::contains otherwise".
> Indeed; see also std::erase/erase_if, although for them there isn't even
> a way to do the "otherwise" part -- the container must offer its own
> overload, which effectively makes them customization points.
> My 2 c,

The difference here is that what the "erase" functions do
*fundamentally* cannot be done on a range. Ranges are sequences of
elements, but they do not have a way to structurally manipulate the
sequence of elements. The *contents* of those elements, yes. The
actual sequence, no. As such, the "erase" class of functions do what
the `remove` functions do, but they also include the container
operations that actually get those elements out of the sequence.

This is why they rely on the existence of member functions.

That is not really the case for `contains`. Well it is, but it's also not.

Like with "erase", what "contains" might do depends on the container
itself. But unlike "erase", there is some reasonable, conceptual
default functionality: search through the container in sequence for
the item.

But there are problems even with that. Associative container
"contains" doesn't necessarily work like sequential container
"contains" functions. And this is true at the API level. A sequential
container "contains" function looks for equality with an element. An
associative container "contains" function looks for "equality" with a
*key* (or some type comparable with a key), not the actual value type.
So it's really unclear to me when you would be in template code where
you're not sure if you're working with an associative container or a
sequential range.

And that's ignoring that the equality for one isn't the equality for
the other, as has been pointed out up-thread.

No, this all just doesn't seem viable. ranges::contains is good enough
for sequential searches for elements. If you need container-specific
functionality, then you should know what the container is doing.

Received on 2023-12-24 20:41:34