To support heterogeneous key lookup for a std::map
one has to be a bit more verbose that in the olden days: (taken from the question on how to do it)
int main()
{
{
puts("The C++11 way makes a copy...");
std::map<std_string, int> m;
auto it = m.find("Olaf");
}
{
puts("The C++14 way doesn't...");
std::map<std_string, int, std::less<>> m;
auto it = m.find("Olaf");
}
}
Also see: https://www.cppstories.com/2021/heterogeneous-access-cpp20/ for an explanation.
From this link and from the linked question (and also from N3657) there a a few scattered reasons given as to why this is opt-in. Since I had to do quite some scrolling and I didn't find a succinct summary of the reasons, I would like to put together a summary here that every junior dev understands, as to
Why stupid C++ makes me write that extra
std::less<>
??! Why doesn't it just allow transparent heterogeneous comparison with the default type we always used?
;-)
If std::map
would simple support this silently, that is if std::map<KeyT, ValT>
would support find(LookupT)
for "any compatible" type then:
double
and int
that would be trouble:implicitly supporting heterogeneous lookup can be dangerous, as the relationship between values might not be maintained after conversions. For example,
1.0 < 1.1
, butstatic_cast<int>(1.0) == static_cast<int>(1.1)
. Thus, using adouble
to look up a value in astd::set<int>
could lead to incorrect results.
Consider there exists for some type
stupid_string
only a converting constructor fromchar const*
but not a comparison operatoroperator<(stupid_string const&, char const*)
, onlyoperator<(stupid_string const&, stupid_string const&)
. Sincestd::less<>
((would)) forward to the comparison operator, each comparison will create a new stupid_string.
((instead of just creating the extra comparison object once on the call site of std::find))