Proposal
N3657 added the following heterogeneous lookup functions in the presence of a
`Compare::is_transparent` tag:
find
count
lower_bound
upper_bound
equal_range
However, heterogeneous keys are not supported for modifiers. My use case is wanting to use a
`string_view` as a key into a
`map<string, X>`. For efficiency, I only want a
`string` to be constructed if the entry doesn't already exist.
auto count_k_mers(std::string_view s, std::size_t length) {
std::map<std::string, std::size_t, std::less<>> counts;
for (std::size_t i = 0; i < s.length() - length + 1; ++i) {
++counts[s.substr(i, length)]; // error: no such function `operator[](string_view)`
}
return counts;
}
No overload of
`operator[]` takes a heterogeneous key, hence the compilation error. The same is true for
`try_emplace`:
++counts.try_emplace(k_mer).first->second; // error: no such function `try_emplace(string_view)`
I can't use
`emplace` naively because that will create a
`string` on every call. Instead, I am forced to do something like this:
auto count_k_mers(std::string_view s, std::size_t length) {
std::map<std::string, std::size_t, std::less<>> counts;
for (std::size_t i = 0; i < s.length() - length + 1; ++i) {
auto k_mer = s.substr(i, length);
auto it = counts.find(k_mer);
if (it == counts.end()) {
it = counts.emplace(k_mer, std::size_t()).first;
}
++it->second;
}
return counts;
}
This could obviously be optimized by using
`lower_bound` and
`emplace_hint`, but what are the chances the average user will do this? So why not provide a heterogeneous
`operator[]` that gives optimal performance by default?
template <typename K>
T& operator[](K const& k) {
auto it = lower_bound(k);
if (it == end() || Compare()(k, it->first)) {
it = emplace_hint(it, k, T());
}
return it->second;
}
Pretty much any function that takes a key could have a heterogeneous overload (
`at`,
`try_emplace`,
`extract`,
`erase`). Is there some reason these functions don't exist yet?