Date: Wed, 28 Jul 2021 14:15:51 -0500
Hi Barry,
Right...which is why I said the return type of value_for(...) would not be quite like std::optional. So there seem to be four or five options to me:
1. std::map<K, V>::value_for(K const&) -> typename std::map<K, V>::value_handle, where map gains a nested type that behaves like std::optional<V&> would behave. Yuck.
2. std::map<K, V>::value_for(K const&) -> V*, where a bare pointer, or some equivalent, is returned. Also yuck.
3. std::map<K, V>::value_for(K const&) -> std::optional<V&>. Requires convincing the standards committee to support reference-type template arguments for std::optional.
4. Something else I haven't thought of
5. Stop wanting this feature
I think 3 is the ideal solution, but the most unlikely to occur. Option 1 is doable but I assume no one wants to add an additional type to std::map. I fear 5 is the most likely solution, although it would sadden me.
Cheers,
Kyle
> On Jul 28, 2021, at 1:46 PM, Barry Revzin <barry.revzin_at_[hidden]> wrote:
>
>
>
> On Wed, Jul 28, 2021, 1:42 PM Kyle Knoepfel via Std-Proposals <std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]>> wrote:
> Hi all,
>
> C++20 added the std::set::contains and std::map::contains member functions, which perform the equivalent of a find, whose return value is then compared with the appropriate end iterator, resulting in Boolean true or false. We therefore have the nice cleanup:
>
> Pre-C++20: if (set.find(key) != cend(map)) { /* key is present */ }
> Post-C++20: if (set.contains(key)) { /* key is present */ }
>
> For std::map, however, there seems to be less utility for 'contains' as the key's corresponding value is often required if the key is present in the map. For example, this is a common usage pattern:
>
> std::map<std::string, unsigned> ages = …;
> if (auto it = ages.find(name); it != cend(ages)) {
> std::cout << "Age of " << name << ": " << it->second << '\n';
> } else {
> std::cout << name << " not known.\n";
> }
>
> Note all the boilerplate to get to the possibly present value (it->second). In such a case above, 'contains' does not help:
>
> std::map<std::string, unsigned> ages = …;
> if (ages.contains(key)) {
> std::cout
> << "Age of " << name << ": "
> << ages.at <http://ages.at/>(key) // Unnecessarily expensive for value guaranteed to be present
> << '\n';
> } else {
> std::cout << key << " not known.\n";
> }
>
> This situation can be made simpler using an interface with std::optional-like semantics:
>
> std::map<std::string, unsigned> ages = …;
> if (auto age = ages.value_for(name)) {
> std::cout << "Age of " << name << ": " << *age << '\n';
> } else {
> std::cout << name << " not known.\n";
> }
>
> where the type of age is a handle-like class that refers to the value of the 'name' entry (not quite like std::optional as we don't want to copy the actual value).
>
> Do others find this idea attractive, modulo bike-shedding issues like the function name?
>
> Thanks,
> Kyle
>
>
> Such a function would have to return an optional<T&> or optional<T const&>, which the standard library's implementation doesn't allow.
>
> Barry
Right...which is why I said the return type of value_for(...) would not be quite like std::optional. So there seem to be four or five options to me:
1. std::map<K, V>::value_for(K const&) -> typename std::map<K, V>::value_handle, where map gains a nested type that behaves like std::optional<V&> would behave. Yuck.
2. std::map<K, V>::value_for(K const&) -> V*, where a bare pointer, or some equivalent, is returned. Also yuck.
3. std::map<K, V>::value_for(K const&) -> std::optional<V&>. Requires convincing the standards committee to support reference-type template arguments for std::optional.
4. Something else I haven't thought of
5. Stop wanting this feature
I think 3 is the ideal solution, but the most unlikely to occur. Option 1 is doable but I assume no one wants to add an additional type to std::map. I fear 5 is the most likely solution, although it would sadden me.
Cheers,
Kyle
> On Jul 28, 2021, at 1:46 PM, Barry Revzin <barry.revzin_at_[hidden]> wrote:
>
>
>
> On Wed, Jul 28, 2021, 1:42 PM Kyle Knoepfel via Std-Proposals <std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]>> wrote:
> Hi all,
>
> C++20 added the std::set::contains and std::map::contains member functions, which perform the equivalent of a find, whose return value is then compared with the appropriate end iterator, resulting in Boolean true or false. We therefore have the nice cleanup:
>
> Pre-C++20: if (set.find(key) != cend(map)) { /* key is present */ }
> Post-C++20: if (set.contains(key)) { /* key is present */ }
>
> For std::map, however, there seems to be less utility for 'contains' as the key's corresponding value is often required if the key is present in the map. For example, this is a common usage pattern:
>
> std::map<std::string, unsigned> ages = …;
> if (auto it = ages.find(name); it != cend(ages)) {
> std::cout << "Age of " << name << ": " << it->second << '\n';
> } else {
> std::cout << name << " not known.\n";
> }
>
> Note all the boilerplate to get to the possibly present value (it->second). In such a case above, 'contains' does not help:
>
> std::map<std::string, unsigned> ages = …;
> if (ages.contains(key)) {
> std::cout
> << "Age of " << name << ": "
> << ages.at <http://ages.at/>(key) // Unnecessarily expensive for value guaranteed to be present
> << '\n';
> } else {
> std::cout << key << " not known.\n";
> }
>
> This situation can be made simpler using an interface with std::optional-like semantics:
>
> std::map<std::string, unsigned> ages = …;
> if (auto age = ages.value_for(name)) {
> std::cout << "Age of " << name << ": " << *age << '\n';
> } else {
> std::cout << name << " not known.\n";
> }
>
> where the type of age is a handle-like class that refers to the value of the 'name' entry (not quite like std::optional as we don't want to copy the actual value).
>
> Do others find this idea attractive, modulo bike-shedding issues like the function name?
>
> Thanks,
> Kyle
>
>
> Such a function would have to return an optional<T&> or optional<T const&>, which the standard library's implementation doesn't allow.
>
> Barry
Received on 2021-07-28 14:15:54