C++ Logo

std-proposals

Advanced search

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

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Tue, 2 Jan 2024 20:35:27 -0500
On Tue, Jan 2, 2024 at 4:46 PM Robert Sitton <robert.sitton_at_[hidden]> wrote:
>
> I fully understand the concerns that have been raised about the proposed std::contains function. However, it's important to emphasize that this function is specifically designed to simplify common coding tasks. While containers and ranges serve distinct purposes, having a unified std::contains function can greatly benefit developers by promoting code consistency and simplifying template code that works with various data structures.

OK, that's an interesting position. You say that it is "specifically
designed to simplify common coding tasks."

Got any evidence for that? Specifically, the whole "common coding
task" part. Because the thing you may not be fully understanding is
the narrowness of the use case here.

If code knows what container it is dealing with, then the user will
just use its existing interface to access it. Even if the user only
knows that it's a sequence range, they'd just call `std::find` or some
equivalent. Therefore, the only reason you'd use this `std::contains`
function is if you *don't* know what you're dealing with. Where the
"container" you've been given could be a sequence container, an
associative container, an unordered associative container, or
something else.

I don't know of any code I've come across which is so completely blind
to the very nature of the range it has been given, yet needs to do a
very specific access operation whose fundamental nature will vary
based on the nature of that range (elements of a set don't have to
have "equality", while elements of a sequence range do; elements of a
set can be compared against things that aren't even of the same type,
etc). At the very least, I strongly contest that this is a "common
coding task" for C++ programmers.

> The introduction of this function aligns with C++'s goal of providing standard, intuitive solutions for everyday programming tasks. It offers the flexibility to customize behavior when needed, making it a valuable addition to the C++ standard library (akin to std::find).
>
> Sincerely,
>
> Robert
>
> On Sun, Dec 24, 2023, 2:41 PM Jason McKesson via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>
>> 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.
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2024-01-03 01:35:40