С++ 11: Существуют ли причины, по которым некоторые обычные типы не должны иметь `std:: hash`?

С регулярным типом я имею в виду определение Степанова в Элементах программирования, в основном, что существует понятие равенства и объекты, которые являются копиями друг друга, сравниваются равными.

Итак, когда у вас есть обычный тип T, и отношение равенства является транзитивным (a == b && b == c = > a == c), вы можете определить (нетривиальный) хэш-функции, которая согласуется с определением равенства (a == b = > h (a) == h (b)). Всегда.

Но стандарт не включает в себя многие std::hash специализации. Например. std::complex не имеет одного и не имеет контейнеров с заметными исключениями vector<bool> и bitset.

Так что мне интересно, какой принцип дизайна здесь.

Или, спросил по-другому: есть ли причины не предоставлять std::hash специализации для ваших собственных типов, если они регулярны, а равенство транзитивно?

Ответы

Ответ 1

Да.

Если тип имеет следующие два свойства, я не думаю, что вы должны определить std::hash:

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

  • Нет эффективного и/или интуитивного способа выбора согласованного подмножества данных для хеша.

Ответ 2

Предоставление специализации для собственных типов не имеет смысла, если они являются шаблонами классов, поскольку хэш-функция (с высокой степенью вероятности) также зависит от типы параметров шаблона, которые неизвестны.

Нет параметров шаблона, или параметры шаблона ограничены определенными типами

// provide no implementation to restrict all types
template<typename T> container;

// int is allowed
template<> container<int> {
    ...
}

// double is allowed
template<> container<double> {
    ...
}

предоставление специализации std::hash возможно, так как реализации классов (или инстанцированных классов шаблонов) известны, как и для vector<bool> вопреки complex<T>.