
On 12/16/24 13:35, Ivan Matek via Boost wrote:
Hi everybody,
I presume somebody thought of this before but for some reason it never happened, but just in case it was never discussed I wonder if people here believe adding an nicer version of find(with different name obviously) to associative containers in boost would be beneficial?
Since boost::optional allows references this would work.
I presume naming is what most people will have strong feeling about. I personally prefer ofind/oat since I love short names, Barry suggested different names in his blog https://brevzin.github.io/c++/2023/05/23/map-api/, e.g. try_at.
As a general comment on the article, I do use the iterator returned from find(), lower_bound() etc. quite often (e.g. to later pass it to erase() or as a hint to insert()), so I disagree with the suggestion that an iterator return is somehow suboptimal. This is the fundamental interface upon which every other, including the one returning optional, could be built, if needed. So I see it as the most optimal one, as it provides the most flexibility to the user. Adding find() overloads to containers means adding a dependency on boost::optional, which makes the container a more heavy dependency for the users. Since containers are often used as data members in classes, this increase in source code footprint arguably will be fairly visible across user's code base. Another downside is that as soon as you choose boost::optional as a return value, proponents of std types everywhere will complain that the new interface doesn't compose well in their code bases. You couldn't choose std::optional as it doesn't support references (yet?), but if it did at some point, it would mean requiring a very recent C++ version, which will be a regression in compatibility for the existing Boost libraries. It would also exacerbate the boost::optional vs. std::optional argument. An alternative would be to return a pointer instead of an optional, but eliminates the main benefit of the addition in the first place. Which is the addition is a more succinct syntax for testing and transforming the found value. Personally, I don't see myself using this syntax very often, if ever, because in my experience the mapped value is rarely as simple as an int, and I almost never want to construct a default value when one is not found in the container. My mental model is that constructing an object has a non-insignificant cost to it, and I should avoid it, if possible. However, I understand that other people may have different experiences, and there the proposed syntax could be more useful. I don't think the benefits outweigh the costs in this case. It may be useful to have an external adapter of the same effect though: template< typename Range, typename... Args > optional< typename Range::const_reference > ofind(Range const& r, Args&&... args) { using result_type = optional< typename Range::const_reference >; auto it = r.find(std::forward< Args >(args)...); return it == r.end() ? result_type{} : result_type(*it); } Note that I'm intentionally using a variadic form to allow for passing an ordering function to polymorphic find() e.g. in Boost.Intrusive containers.