program story

std :: hash를 전문화하는 방법

inputbox 2020. 8. 27. 07:46
반응형

std :: hash를 전문화하는 방법:: operator () 순서가 지정되지 않은 컨테이너의 사용자 정의 유형에 대해?


에 사용자 정의 키 유형을 지원하기 위해 std::unordered_set<Key>그리고 std::unordered_map<Key, Value>하나는 제공해야 operator==(Key, Key)하고 해시 펑터 :

struct X { int id; /* ... */ };
bool operator==(X a, X b) { return a.id == b.id; }

struct MyHash {
  size_t operator()(const X& x) const { return std::hash<int>()(x.id); }
};

std::unordered_set<X, MyHash> s;

그냥 쓸 더 편리 할 것 std::unordered_set<X>로모그래퍼 기본 해시 유형에 대한 X유형 컴파일러 및 라이브러리와 함께 주셔서처럼. 상담 후

  • C ++ 표준 초안 N3242 §20.8.12 [unord.hash] 및 §17.6.3.4 [hash.requirements],
  • 부스트.
  • g ++ include\c++\4.7.0\bits\functional_hash.h
  • VC10 include\xfunctional
  • Stack Overflow의 다양한 관련 질문

전문화가 가능한 것 같습니다 std::hash<X>::operator().

namespace std { // argh!
  template <>
  inline size_t 
  hash<X>::operator()(const X& x) const { return hash<int>()(x.id); } // works for MS VC10, but not for g++
  // or
  // hash<X>::operator()(X x) const { return hash<int>()(x.id); }     // works for g++ 4.7, but not for VC10 
}                                                                             

C ++ 11에 대한 컴파일러 지원이 아직 실험적이라는 점을 감안할 때 --- 나는 Clang을 시도하지 않았습니다 ----, 내 질문은 다음과 같습니다.

  1. 이러한 전문화를 네임 스페이스에 추가하는 것이 합법적 std입니까? 나는 그것에 대해 복잡한 감정을 가지고 있습니다.

  2. 어떤 std::hash<X>::operator()버전이있는 경우 C ++ 11 표준을 준수합니까?

  3. 휴대용 방법이 있습니까?


네임 스페이스 * 전문화추가 하는 것이 명시 적으로 허용되고 권장됩니다 std. 해시 함수를 추가하는 올바른 (기본적으로 유일한) 방법은 다음과 같습니다.

namespace std {
  template <> struct hash<Foo>
  {
    size_t operator()(const Foo & x) const
    {
      /* your code here, e.g. "return hash<int>()(x.value);" */
    }
  };
}

(지원을 고려할 수있는 기타 인기있는 전문 분야는 std::less, std::equal_tostd::swap입니다.)

*) 관련된 유형 중 하나가 사용자 정의 된 한, 나는 가정한다.


내 베팅은 unorder_map / unorder_set / ... 클래스의 Hash 템플릿 인수에 있습니다.

#include <unordered_set>
#include <functional>

struct X 
{
    int x, y;
    std::size_t gethash() const { return (x*39)^y; }
};

typedef std::unordered_set<X, std::size_t(*)(const X&)> Xunset;
typedef std::unordered_set<X, std::function<std::size_t(const X&)> > Xunset2;

int main()
{
    auto hashX = [](const X&x) { return x.gethash(); };

    Xunset  my_set (0, hashX);
    Xunset2 my_set2(0, hashX); // if you prefer a more flexible set typedef
}

물론이야

  • hashX는 전역 정적 함수일 수 있습니다.
  • 두 번째 경우에는 통과 할 수 있습니다.
    • the oldfashioned functor object (struct Xhasher { size_t operator(const X&) const; };)
    • std::hash<X>()
    • any bind expression satisfying the signature -

@Kerrek SB has covered 1) and 3).

2) Even though g++ and VC10 declare std::hash<T>::operator() with different signatures, both library implementations are Standard compliant.

The Standard does not specify the members of std::hash<T>. It just says that each such specialization must satisfy the same "Hash" requirements needed for the second template argument of std::unordered_set and so on. Namely:

  • Hash type H is a function object, with at least one argument type Key.
  • H is copy constructible.
  • H is destructible.
  • If h is an expression of type H or const H, and k is an expression of a type convertible to (possibly const) Key, then h(k) is a valid expression with type size_t.
  • If h is an expression of type H or const H, and u is an lvalue of type Key, then h(u) is a valid expression with type size_t which does not modify u.

참고URL : https://stackoverflow.com/questions/8157937/how-to-specialize-stdhashkeyoperator-for-user-defined-type-in-unordered

반응형