Как расширить 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.
Другие вопросы по тегам