2015-06-24 4 views
4

Как я могу добавить (неуказанный статический) unordered_set в unordered_map, без необходимости копировать неупорядоченный_set?emplace unordered_set in unordered_map

Я попытался это:

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)’ 
+0

Это похоже на то, что вы хотите 'unordered_map'' unordered_set '(что не то, что вы говорите в вопросе). Просьба уточнить. – Walter

ответ

9

Исправленные инициализаторы - это один из краевых случаев, когда идеальная пересылка не настолько совершенна.

Проблема в том, что согласованные инициализаторы, переданные параметрам шаблона функции, находятся в невыводимом контексте, а компиляторам не разрешено выводить для них тип.

К счастью, исправление довольно просто: просто укажите, пожалуйста, об использовании 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*>.

2

Элементы карт (оба map и unordered_map) имеют тип using value type = std::pair<key_t, mapped_type>. Поэтому emplace не передает свои аргументы в конструктор unordered_set<string>!

После того, как вы понимаете, что решение 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"}); 
1

Для того, чтобы вставить что-то в 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"}))); 

и вам должно быть хорошо идти.

+0

Временное уже значение rvalue, поэтому 'std :: move', который вы скопировали из OP, бессмысленно. – user2079303

+0

Хорошо, спасибо, что указали это! – haavee

+4

Я думаю, вы имели в виду 'std :: make_pair' вместо' std :: pair'? – davidhigh

2

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

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

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

+0

Не копирует ли этот код неупорядоченный_set? –

+0

Нет, 'unordered_map :: emplace' принимает ссылку rvalue и пересылает ее в контейнер. Нет копии, только шаг. – davidhigh

Смежные вопросы