Как расширить std :: tr1 :: hash для пользовательских типов? - PullRequest
22 голосов
/ 15 марта 2009

Как мне разрешить реализации STL подбирать мои пользовательские типы? На MSVC есть класс std::tr1::hash, который я могу частично специализировать, используя

namespace std 
{
    namespace tr1 
    { 
        template <> 
        struct hash<MyType> 
        { ... };
    } 
}

но это рекомендуемый способ? Кроме того, это работает с реализацией GCC? Для boost::hash достаточно предоставить бесплатную функцию size_t hash_value (const MyType&), есть ли что-то похожее для реализации TR1?

Ответы [ 4 ]

21 голосов
/ 05 апреля 2009

Я пытался выработать точный синтаксис для этого с неупорядоченными ассоциативными контейнерами (также используя 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 */;
       }
   };
}}

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

4 голосов
/ 15 марта 2009

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

3 голосов
/ 15 марта 2009

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

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

0 голосов
/ 05 мая 2011

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