Как расширить std::tr1::hash для пользовательских типов?
Как я могу позволить реализации STL забирать мои пользовательские типы? На MSVC есть класс std::tr1::hash
, который я могу частично специализировать, используя
namespace std
{
namespace tr1
{
template <>
struct hash<MyType>
{ ... };
}
}
но это рекомендуемый способ? Кроме того, это работает с реализацией GCC? За boost::hash
достаточно предоставить бесплатную функцию size_t hash_value (const MyType&)
Есть ли что-то подобное для реализации TR1?
4 ответа
Да, это также будет работать для GCC. Я использую его в большем проекте, и он работает без проблем. Вы также можете предоставить свой собственный класс хеширования для контейнеров TR1, но указано, что std::tr1::hash<> является классом хеширования по умолчанию. Специализировать его для пользовательских типов кажется естественным способом расширить стандартную функциональность хеширования.
Я пытался определить точный синтаксис для этого с неупорядоченными ассоциативными контейнерами (также используя GCC, как спрашивал ОП) и задал этот вопрос.
К сожалению, он не опустился до уровня детализации, который я хотел. Просматривая заголовки gcc о том, как они реализовали стандартные хеш-функции, я понял, как это работает. Ввиду нехватки примеров (по крайней мере, на момент написания) в Интернете, я подумал, что это будет хорошим местом для публикации моего собственного примера (который я могу подтвердить работами с GCC):
namespace std { namespace tr1
{
template <>
struct hash<MyType> : public unary_function<MyType, size_t>
{
size_t operator()(const MyType& v) const
{
return /* my hash algorithm */;
}
};
}}
(обратите внимание, что здесь есть два пространства имен - это просто мое соглашение для свертывания вложенных пространств имен)
Поскольку вы не добавляете в std
Пространство имен библиотеки, но только с предоставлением специализаций, тогда это совершенно нормально.
Если вы хотите обеспечить более общий подход к хешированию (например, хеш для кортежей в целом), взгляните на Boost Fusion. Вот простой пример, который будет работать в большинстве случаев (возможно, за исключением кортежа кортежей)
Следующий фрагмент кода показывает, как специализироваться std::tr1::unordered_map
для картированияboost::const_string<char>
в void*
аналогично тому, как std::string
хэшируется
#include <boost/const_string/const_string.hpp>
typedef class boost::const_string<char> csc;
namespace std
{
namespace tr1
{
template <>
struct hash<csc> {
public:
size_t operator()(const csc & x) const {
return std::_Hash_impl::hash(x.data(), x.size());
}
};
}
}
typedef std::tr1::unordered_map<csc, void*> Map;
typedef Map::value_type Dual; ///< Element Type.