2015-04-27 3 views
4

Я пытался специализировать хэш для моего собственного типа, шаблонного ключа.Специализирующийся std :: hash для templated Key

Я основывался на нем cppreference.

Я получаю ошибку компиляции «Стандарт C++ не предоставляет хэш для этого типа». Я полагаю, я просто сделал это неправильно. Может ли компилятор даже поддерживать такой шаблон?

namespace std { 
    template<typename SType, typename AType, typename PType> 
    struct MyKey { 
     const SType from; 
     const AType consume; 
     const PType pop; 
    }; 

    template<typename SType, typename AType, typename PType> 
    struct hash<MyKey<SType, AType, PType>> { 
     size_t operator()(MyKey const &key) { 
      std::hash<SType>()(key.from); 
      std::hash<AType>()(key.consume); 
      std::hash<PType>()(key.pop); 
     } 
    }; 
} 
+0

Вы должны научить компилятор, как хэширования ваших типов - не просто 'MyKey', но' SType'. 'AType' и' PType' тоже (по крайней мере те, которые не являются 'typedef' для известных типов). После того, как вы это сделали, хеш MyKey не должен просто вызывать хеш-функции переменной-члена, он должен возвращать значение hash_combine'd, включающее хэши этих переменных-членов. Есть *** много *** из существующих вопросов, объясняющих это. –

ответ

3

Есть несколько проблем с вашим кодом:

Вы не разрешается размещать новые определения или объявления в std Into имен; допускаются только специализации (например, std::hash). Поэтому ваш шаблон MyKey должен быть удален из пространства имен std.

Неправильная подпись вашего operator(). MyKey не называет тип, вам нужно явно его паратизировать. Кроме того, оператор должен быть помечен const.

std::hash специализация должна предоставлять типы элементов argument_type и result_type.

Если нет существующих специализаций для типов, переданных как SType и т. Д., Вам необходимо предоставить их сами.

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

Реализация, будет составлять для типов, которые имеют свою собственную std::hash специализации:

//moved out of std 
template<typename SType, typename AType, typename PType> 
struct MyKey { 
    const SType from; 
    const AType consume; 
    const PType pop; 
}; 

namespace std { 
    template<typename SType, typename AType, typename PType> 
    struct hash<MyKey<SType, AType, PType>>{ 
     //member types 
     using argument_type = MyKey<SType,AType,PType>; 
     //arguments specified  ^ ^ ^
     using result_type = std::size_t; 

     result_type operator()(argument_type const& key) const { 
     //marked const         ^
      //these will fail if SType and friends don't have a std::hash specialization 
      result_type s_hash = std::hash<SType>()(key.from); 
      result_type a_hash = std::hash<AType>()(key.consume); 
      result_type p_hash = std::hash<PType>()(key.pop); 

      //in your actual code, you'll want to compute the return type from the above 
      return p_hash; 
     } 
    }; 
}