Как скопировать unordered_map с помощью ключа const? - PullRequest
6 голосов
/ 11 марта 2019

Простой код:

#include <unordered_map>

int main()
{
  std::unordered_map<const int, int> m;
  std::unordered_map<const int, int> m1 = m;
}

выдает извилистое сообщение об ошибке компиляции:

Ошибка C2280 'std :: hash <_Kty> :: hash (void)': попыткассылка на удаленную функцию

, которая в основном говорит, что unordered_map во внутреннем устройстве не ожидает, что ключ будет постоянным

PS : я прочитал ответ на аналогичный вопрос:

Ассоциативные контейнеры представляют только пару (ключ, значение) как std :: pair, поэтому дополнительное const для типа ключа является излишним.

Но это не объясняет, почему хеш-карту с ключом const практически невозможно использовать и как обойти проблему

1 Ответ

7 голосов
/ 11 марта 2019

Тип

std::unordered_map<const int, int> 

использует третий параметр по умолчанию std::hash<const int>. Этот тип хеша, в отличие от std::hash<int>, не специализируется стандартной библиотекой, как и deleted (как говорится в сообщении об ошибке).

Рабочий хеш требуется при копировании unordered_set. Чтобы создать рабочий хеш:

  1. Вы можете специализировать std::hash<const int> самостоятельно, чтобы он больше не удалялся:

    namespace std 
    { 
      // fixes it but is a bad idea - could break in future revisions of the standard
      template<>
      struct hash<const int> : hash<int>{};
    }
    
  2. Или вы можете явно указать свой хеш:

    std::unordered_map<const int, int, std::hash<int>> 
    
  3. Или вы можете избавиться от const в ключе (так как он не действует):

    std::unordered_map<int, int> 
    

Добавление

Удалено означает, что конструктор неспециализированной std::hash удален:

template <typename T>
struct hash
{
   hash() = delete;
   hash(const hash) = delete;
   // more deleted methods
};

"удалено" означает, что оно не существует (ни предоставлено пользователем, ни по умолчанию).

Вы можете увидеть это в cppreference , где они используют терминологию включенного / выключенного:

Для каждого типа Key, для которого ни библиотека, ни пользователь не предоставляют включенную специализацию std :: hash, эта специализация существует и отключена.

Поскольку std::hash<const int> не предоставляется библиотекой, она отключается, если она не предоставлена ​​пользователем. Далее в тексте объясняется, что отключено :

Отключенные специализации не удовлетворяют Hash, [...] std :: is_default_constructible_v, std :: is_copy_constructible_v [...] все ложные. Другими словами, они существуют, но не могут быть использованы.

Итак, эти конструкторы должны быть недоступны (и удаление их - лучший способ сделать это).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...