How can I add a (statically defined) unordered_set to an unordered_map, without having to copy the unordered_set?
I tried this:
std::unordered_map<int, std::unordered_set<std::string>> my_map;
for (int i=0; i<100; i++)
my_map.emplace(i, {"foo", "bar"});
and this:
std::unordered_map<int, std::unordered_set<std::string>> my_map;
for (int i=0; i<100; i++)
my_map.insert(i, std::move(std::unordered_set<std::string>({"foo", "bar"})));
but none of them compiles, I get these errors (respectively):
error: no matching function for call to ‘std::unordered_map<int, std::unordered_set<std::basic_string<char> > >::emplace(int&, <brace-enclosed initializer list>)’
and
error: no matching function for call to ‘std::unordered_map<int, std::unordered_set<std::basic_string<char> > >::insert(int&, std::remove_reference<std::unordered_set<std::basic_string<char> > >::type)’
Braced initializers are one of the edge cases that perfect forwarding is not so perfect about.
The issue is that braced initializers passed to function template parameters are in a non-deduced context and compilers are not allowed to deduce a type for them.
Luckily, the fix is pretty easy: just be explicit about the use of std::initializer_list
.
my_map.emplace(i, std::initializer_list<std::string>{"foo", "bar"});
The usual way to solve this issue is by doing something like:
auto list = { "foo", "bar" };
my_map.emplace(i, list);
But this doesn't work for std::string
s because decltype(list)
is deduced as std::initializer_list<const char*>
.
The elements of maps (both map
and unordered_map
) are of type using value type = std::pair<key_t, mapped_type>
. Therefore, emplace
does not pass its arguments to the unordered_set<string>
constructor!
Once you realize that, the solution is easy:
std::unordered_map<int, std::unordered_set<std::string>> my_map;
for (int i=0; i<100; i++)
my_map.emplace(i, std::unordered_set<std::string>{"foo", "bar"});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With