Использовать 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"})));

и тебе должно быть хорошо идти.

Другие вопросы по тегам