Использование неупорядоченной карты с массивами в качестве ключей
Я не понимаю, почему я не могу иметь unordered_map
с array<int,3>
в качестве типа ключа:
#include <unordered_map>
using namespace std;
int main() {
array<int,3> key = {0,1,2};
unordered_map< array<int,3> , int > test;
test[key] = 2;
return 0;
}
Я получаю длинную ошибку, наиболее уместной частью которой является
main.cpp:11:9: error: no match for ‘operator[]’ (operand types are std::unordered_map<std::array<int, 3ul>, int>’ and ‘std::array<int, 3ul>’)
test[key] = 2;
^
Массивы не могут быть ключами, потому что они пропускают некоторые требования?
4 ответа:
Но почему?
Как упоминалось в http://www.cplusplus.com/reference/unordered_map/unordered_map/
Внутри, элементы в unordered_map не сортируются ни в одном определенный порядок относительно их ключевых или отображенных значений, но организованы в ведра в зависимости от их хэш-значений, чтобы обеспечить быстрый доступ к отдельным элементам непосредственно по их ключевым значениям (с постоянная средняя временная сложность в среднем).
Теперь в соответствии с вашим вопросом нам нужно
hash
массив, который не был реализован внутренне в стандартном c++.Как с этим покончить?
Поэтому, если вы хотите сопоставить
array
значению, вы должны реализовать свой собственный std:: hash http://en.cppreference.com/w/cpp/utility/hash для чего вы могли бы получить некоторую помощь от C++ как вставить массив в хэш-набор?.Некоторые обходят
Если вы свободны использовать
boost
, то он может предоставить вам хеширование массивов и многих других типов. Он в основном использует методhash_combine
, для которого вы можете посмотреть на http://www.boost.org/doc/libs/1_49_0/boost/functional/hash/hash.hpp .
Соответствующая ошибка равна
error: no match for call to '(const std::hash<std::array<int, 3ul> >) (const std::array<int, 3ul>&)'
unordered_map
требуется хэш ключа, и для этого он ищет перегрузкуstd::hash
. Вы можете расширитьnamespace std
с помощью подходящей хэш-функции.
Вы должны реализовать хэш. Хэш-таблицы в зависимости от хеширования ключа, чтобы найти ведро, чтобы положить их в него. C++ волшебным образом не знает, как хэшировать каждый тип, и в данном конкретном случае он не знает, как хэшировать массив из 3 целых чисел по умолчанию. Вы можете реализовать простую хэш-структуру следующим образом:
struct ArrayHasher { std::size_t operator()(const std::array<int, 3>& a) { std::size_t h = 0; for (auto e : a) { h ^= std::hash<int>{}(e) + 0x9e3779b9 + (h << 6) + (h >> 2); } return h; } };
И затем использовать его:
unordered_map< array<int,3> , int, ArrayHasher > test;
Edit: я изменил функцию для объединения хэшей с наивного xor на функцию, используемую boost для этой цели: http://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html. Это должно быть достаточно надежна, чтобы на самом деле использовать.