2016-07-28 9 views
1

Исходная проблема довольно длинная, поэтому я упрощаю ее здесь.Проблемы при использовании unordered_set как ключа unordered_map, в C++

Мне нужно создать группу строк с уместным целым числом, скажем, группой тренировок. Затем мне нужно создать много тренировочных групп. Я хочу управлять всеми учебными группами в одном контейнере. Поэтому я решил использовать boost :: unordered_map <> с ключом std :: unordered_set. Потому что BOOST имеет хэш-значение для стандартного контейнера C++.

Упрощенный код следующим образом:

#include <string> 
#include <unordered_set> 
#include <utility> 
#include<boost/unordered_map.hpp> 

using namespace std; 

int main() 
{ 
    boost::unordered_map< unordered_set<string>, int> training_groups; 
    pair<unordered_set<string>, int> a_training_group; 
    training_groups.insert(a_training_group); 
    return 0; 
} 

Однако код не компилируется успешно. Существует множество загадочных предупреждений и ошибок. Ошибка заключается в следующем:

1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(30): error C2440: 'type cast' : cannot convert from 'const std::unordered_set<std::string,std::hash<_Kty>,std::equal_to<_Kty>,std::allocator<_Kty>>' to 'size_t' 
1>   with 
1>   [ 
1>    _Kty=std::string 
1>   ] 
1>   No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 
1>   C:\Program Files\boost\boost_1_59_0\boost/functional/hash/extensions.hpp(262) : see reference to function template instantiation 'size_t stdext::hash_value<T>(const _Kty &)' being compiled 
1>   with 
1>   [ 
1>    T=std::unordered_set<std::string,std::hash<std::string>,std::equal_to<std::string>,std::allocator<std::string>> 
1> ,   _Kty=std::unordered_set<std::string,std::hash<std::string>,std::equal_to<std::string>,std::allocator<std::string>> 
1>   ] 

Я не знаю, где происхождение этой ошибки и как ее решить. Если компилятор не может выполнить хеш-функцию unordered_set, информация об ошибке будет содержать слова типа «Хэш» или «Ключ». Однако он просто говорит о преобразовании типов, который похож на хеш-функцию. Поэтому я чувствую смущение.

Может кто-нибудь дать совет. Я использую Visual Studio 2013 в Windows 8.

PS: когда я сменил ключ unordered_set<string> на set<string> или vector<string>, программа успешно скомпилируется. Но я до сих пор не знаю причины и не знаю, как решить проблему, если я намерен использовать в качестве ключа unordered_set<string>.

+0

почему вы думаете, должны набор быть ключом к карте? –

+1

Для моей реальной проблемы вторая часть тренировочной группы - это фактически другой неупорядоченный_определенный тип> определенного типа. В этой статье я использую целое число для упрощения вопроса. Таким образом, по сравнению с unordered_set <> для самоопределяемого типа, в качестве ключа лучше использовать unordered_set <>. Кроме того, я могу изменить Key unordered_set <>, чтобы просто установить <> или vector <>. Однако unordered_set <> удобнее и быстрее для будущих манипуляций. –

+0

@JohnSmith: Использование 'unordered_set' в качестве ключа действительно не очень быстро, так как предикат сравнения очень медленный. Он может быть квадратичным в заданном размере (именно потому, что сбор неупорядочен). – rici

ответ

1

Boost делает не обеспечивает хеш-функцию для std::unordered_set, список хеш-функций содержит, например, один для std::set:

http://www.boost.org/doc/libs/1_61_0/doc/html/hash/reference.html#idp6283424-bb

Таким образом, вы должны предоставить свой собственный хэш-функцию, которая относительно легко при использовании boost::hash_range:

#include <string> 
#include <unordered_set> 
#include <utility> 
#include <boost/functional/hash/hash_fwd.hpp> 

namespace boost 
{ 
template <class K, class C, class A> 
std::size_t hash_value(const std::unordered_set<K, C, A>& v) 
{ 
    return boost::hash_range(v.begin(), v.end()); 
} 
} // namespace boost 

#include <boost/functional/hash.hpp> 
#include <boost/unordered_map.hpp> 
int main() 
{ 
    boost::unordered_map<std::unordered_set<std::string>, int> training_groups; 
    std::pair<std::unordered_set<std::string>, int> a_training_group; 
    training_groups.insert(a_training_group); 
    return 0; 
} 

live example

+0

Большое спасибо. Я пропустил, что BOOST не предоставляет хеш-функцию для std :: unordered_set. Кстати, std :: unordered_set считается стандартным контейнером C++? –

+2

Да, это легко обеспечить хэш-функцию для std :: unordered_set. Хеш-функция, которая работает, немного сложнее. Почему вы думаете, что повышение не дает этого? Подсказка: связанная вами страница говорит, почему. –

+0

@JohnSmith: ['std :: unordered_set'] (http://en.cppreference.com/w/cpp/container/unordered_set) является частью стандартной библиотеки C++ с C++ 11. – rici