Date: Wed, 28 Jul 2021 13:40:48 -0500
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(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
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(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
Received on 2021-07-28 13:41:28