поместить 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)’

person Valentin Lorentz    schedule 24.06.2015    source источник
comment
Это больше похоже на то, что вы хотите unordered_map из unordered_set (это не то, что вы говорите в вопросе). Просьба уточнить.   -  person Walter    schedule 24.06.2015


Ответы (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::strings, потому что decltype(list) выводится как std::initializer_list<const char*>.

person TartanLlama    schedule 24.06.2015

Элементы карт (как 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"});
person gha.st    schedule 24.06.2015

Вы можете использовать следующий код:

for (int i=0; i<100; i++)
  my_map.emplace(i, std::unordered_set<std::string>({"foo","bar"}));

Это переместит неупорядоченный набор в неупорядоченную карту.

person davidhigh    schedule 24.06.2015
comment
Нет, unordered_map::emplace берет ссылку rvalue и перенаправляет ее в контейнер. Нет копии, только ход. - person davidhigh; 24.06.2015

Чтобы что-то вставить в 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"})));

и вы должны быть готовы идти.

person haavee    schedule 24.06.2015
comment
Временное уже является значением r, поэтому std::move, которое вы скопировали из OP, бессмысленно. - person eerorika; 24.06.2015
comment
Я думаю, вы имели в виду std::make_pair вместо std::pair? - person davidhigh; 24.06.2015
comment
Да, действительно. Спасибо! - person haavee; 24.06.2015