
On Tue, Dec 17, 2024 at 3:08 PM Vinnie Falco <vinnie.falco@gmail.com> wrote:
On Mon, Dec 16, 2024 at 10:46 PM Ivan Matek <libbooze@gmail.com> wrote:
On Mon, Dec 16, 2024 at 6:24 PM Vinnie Falco <vinnie.falco@gmail.com> wrote:
Can this be implemented as a free function over the public API of unordered containers? In other words, this signature:
Yes, but it is not like Barry or other people <https://www.youtube.com/watch?feature=shared&t=150&v=kye4aD-KvTU> wanting member functions do not know this.
It seems there are two choices here:
1. Add a member function to uncountably many existing and future unordered containers by adding a member function
2. Write a single, separate free function template which works for all existing and future unordered containers
The member function requires selecting an optional type and including its header, while the free function approach can scale to different optional types (one per free function).
Please explain why we should prefer 1 instead of 2.
There are two related points here 1. member syntax is better for users 2. existing practice Member Syntax is Better for Users Herb's UFCS P3021 <https://open-std.org/JTC1/SC22/WG21/docs/papers/2023/p3021r0.pdf> has a list of reasons explaining this in detail. Since some people mentioned UFCS here before just to make clear: I am linking this paper *not* because of UFCS, but because it explains why member syntax is better for users(sections 3.1.1, 3.1.2, 3.1.3). Existing Practice We have std::basic_string<CharT,Traits,Allocator>::starts_with std::basic_string_view<CharT,Traits>::starts_with although there is(or more precisely there will be) std::ranges::starts_with You may say that having member function 2 times is fine since it duplicated just 2 times, but we also have std::set<Key,Compare,Allocator>::contains std::map<Key,T,Compare,Allocator>::contains std::unordered_set<Key,Hash,KeyEqual,Allocator>::contains std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::contains std::multiset<Key,Compare,Allocator>::contains std::multimap<Key,T,Compare,Allocator>::contains std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::contains std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::contains If you say this is just some modern C++ nonsense: Since C++98 containers had empty member function although it is trivially implementable with free function empty. Here not even talking about "complicated" C++17 std::empty that understands C arrays/std::array/..., talking about simple function that could just take container with size member function. template<typename C> bool empty(const C& c) { return c.size() == 0; } But for decades we have this duplication in member functions since empty is commonly called function. To recap situation is that in C++ we have tension between ease of use of common operations on container vs blowing up it's API size. And as Barry wrote 2 most common operations on map are insertion and lookup. So I believe lookup is definitely important enough to get nicer syntax. few notes regarding suggested free function discussed: 1. Dispatching to member may be confusing. std::ranges::find / std::ranges::contains does not <https://stackoverflow.com/a/75687947/> dispatch to members if available 2. try_find seems like a wrong name. try_at makes sense since at has precondition(unless you use exceptions for control flow :) ), while find does not, i.e. it can fail. So it is kind of weird to have a prefix that says try in algorithm that has same "success rate" as find.