Использовать unordered_set в unordered_map
Как я могу добавить (статически определенный) unordered_set к unordered_map, не копируя unordered_set?
Я попробовал это:
std::unordered_map<int, std::unordered_set<std::string>> my_map;
for (int i=0; i<100; i++)
my_map.emplace(i, {"foo", "bar"});
и это:
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"})));
но ни один из них не компилируется, я получаю эти ошибки (соответственно):
error: no matching function for call to ‘std::unordered_map<int, std::unordered_set<std::basic_string<char> > >::emplace(int&, <brace-enclosed initializer list>)’
а также
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)’
4 ответа
Заключенные в скобки инициализаторы - один из крайних случаев, в которых идеальная пересылка не столь совершенна.
Проблема заключается в том, что инициализированные скобками инициализаторы, передаваемые в параметры шаблона функции, находятся в не выводимом контексте, и компиляторам не разрешается выводить для них тип.
К счастью, исправить это довольно просто: просто откровенно об использовании std::initializer_list
,
my_map.emplace(i, std::initializer_list<std::string>{"foo", "bar"});
Обычный способ решить эту проблему - сделать что-то вроде:
auto list = { "foo", "bar" };
my_map.emplace(i, list);
Но это не работает для std::string
потому что decltype(list)
выводится как std::initializer_list<const char*>
,
Вы можете использовать следующий код:
for (int i=0; i<100; i++)
my_map.emplace(i, std::unordered_set<std::string>({"foo","bar"}));
Это переместит неупорядоченный набор в неупорядоченную карту.
Элементы карт (оба map
а также unordered_map
) имеют тип using value type = std::pair<key_t, mapped_type>
, Следовательно, emplace
не передает свои аргументы unordered_set<string>
конструктор!
Как только вы поймете это, решение станет простым:
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"});
Чтобы вставить что-то в std::map<Key, Value>
нужно вставить std::pair<Key, Value>
Изменить:
my_map.insert(i, std::move(std::unordered_set<std::string>({"foo", "bar"})));
в:
my_map.insert( std::make_pair(i, std::unordered_set<std::string>({"foo", "bar"})));
и тебе должно быть хорошо идти.