Как расширить 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?

Ответ 1

Да, это также будет работать для GCC. Я использую его в более крупном проекте, и он работает без проблем. Вы также можете предоставить собственный собственный хэш-класс для контейнеров TR1, но указано, что std:: tr1:: hash < > является классом хэширования по умолчанию. Специализация для пользовательских типов кажется естественным способом расширения стандартной хэш-функции.

Ответ 2

Я пытался выработать точный синтаксис для этого с неупорядоченными ассоциативными контейнерами (также используя GCC, как спрашивал OP) и ударил этот вопрос.

К сожалению, он не опустился до уровня детализации, который я хотел. Просматривая заголовки 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 */;
       }
   };
}}

(обратите внимание, что здесь есть два пространства имён - это только мое соглашение о сворачивании вложенных пространств имен)

Ответ 3

Поскольку вы не добавляете в пространство имен библиотеки std, но только предоставляете специализации, тогда это нормально.

Если вы хотите предоставить более общий подход хэширования (например, хэш для кортежей в целом), посмотрите на Boost Fusion. Вот простой пример, который будет работать для большинства случаев (вероятно, с исключением для кортежей кортежей)

Ответ 4

В следующем фрагменте кода показано, как специализировать 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.