2011-11-16 4 views
82

std::unordered_set<Key>std::unordered_map<Key, Value> 하나의 사용자 정의 키 유형을 지원하는 것은 operator==(Key, Key)를 제공해야하고 해시 펑 : 유형 X에 대한 기본 해시와 단지 std::unordered_set<X> 를 작성하는 것이 더 편리 할 것std :: hash를 특수화하는 방법 <Key> :: unorder 컨테이너의 사용자 정의 유형에 대한 operator()?

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; 

, 컴파일러 및 라이브러리와 함께 오는 유형의 경우는 입니다. 상담 후

  • C++ 표준 Draft N3242 §20.8.12 [unord.hash] 및 §17.6.3.4 [hash.requirements,
  • Boost.Unordered
  • 그램 ++ include\c++\4.7.0\bits\functional_hash.h
  • VC10 include\xfunctional
  • 에게 다양한 related question (스택 오버플로)

it se 가능한 EMS는 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)는 아직 실험 단계에 대한 감안할 때 컴파일러 지원 --- 내가 연타를 시도하지 않았다 ---이 내 질문은 :

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

  2. std::hash<X>::operator() 버전 중 어느 것이 C++ 11 표준을 준수합니까?

  3. 휴대 할 수있는 방법이 있습니까?

+0

을, 나는 글로벌'연산자 == (CONST 키, CONST 키)를 제공했다 ' –

답변

99

당신은 명시 적으로 허용 * std을 네임 스페이스에 전문를 추가하는 것이 좋습니다. 해시 함수를 추가하는 올바른 (기본적으로 유일한) 방법은 이것이다 : (. 당신이 std::less, std::equal_tostd::swap하는 지원 고려해 볼 수 있습니다 그 다른 인기 전문)

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

*)만큼 관련 유형 중 하나가 사용자 정의입니다.

+1

이것이 가능하지만 일반적으로이 방법을 권장합니다. 재미있는 ADL 비즈니스로 누군가의 하루를 망칠 필요가 없도록 대신'unorder_map 인스턴스화를 선호합니다. (** 편집 ** [이 주제에 대한 Pete Becker의 조언] (http://bytes.com/topic/c/answers/820457-how-have-user-defined-hash-unordered_map)) – sehe

+2

@sehe : 그 주위에 거짓말 해쉬 펑터 (hash functor)가 디폴트 구성 가능 (constructible) 일 가능성이 있지만 어째서? (member-'operator =='를 구현했기 때문에 평등이 더 쉽다.) 나의 일반적인 철학은 함수가 자연적이고 근본적으로 유일한 "올바른"(lexicographic 쌍 비교와 같은) 것이라면, 'std'. 특이한 경우 (순서가 지정되지 않은 쌍 비교와 같음) 컨테이너 유형에 고유하게 지정합니다. –

+1

'size_t 연산자() (const Foo & x) const' 여야합니다. – aschepler

4

@Kerrek SB는 1) 및 3)을 처리했습니다.

2) g ++ 및 VC10이 다른 서명으로 std::hash<T>::operator()을 선언하더라도 두 라이브러리 구현은 모두 표준을 준수합니다.

표준은 std::hash<T>의 구성원을 지정하지 않습니다. 단지 각 전문 분야가 두 번째 템플릿 인수 인 std::unordered_set에 필요한 것과 동일한 '해시'요구 사항을 충족해야한다고 말합니다.즉 :

  • 해시 형 H 함수 객체는 적어도 하나의 인수 유형 Key으로한다.
  • H은 복사 가능합니다.
  • H은 파괴 가능합니다.
  • h 경우 형 H 또는 const H의 표현이고, k는 (아마도 const) Key는 다음 h(k) 유형 size_t있는 유효한 표현으로 변환 타입의 표현이다.
  • h 만약 유형 H 또는 const H의 표현이며, u 유형 Key의 좌변이며, 다음 h(u)u을 수정하지 않는 유형 size_t와 올바른 표현이다.
+0

아니요, 구현은'std :: hash '이 아닌'std :: hash :: operator()'전체를 전문화하려고 시도하고'std :: hash : : operator()'는 구현 정의되어 있습니다. – ildjarn

+0

@ildjarn : Clarified - 시도한 전문 분야가 아니라 라이브러리 구현에 대해 이야기했습니다. 정확히 OP가 물어 보려 던 의도가 확실하지 않습니다. – aschepler

6

내 내기가 unordered_map도/unorder_set에 대한 해시 템플릿 인수에/... 수업이 될 것입니다 : 물론

#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은 단지뿐만 아니라 글로벌 정적이 될 수 함수
  • 두 번째 경우에 전달할 수 있습니다.
    • oldfashioned functor obj 요법 (struct Xhasher { size_t operator(const X&) const; };)
    • std::hash<X>()
    • 어떤 바인딩 표현식이 서명 만족 -
    • GCC 4.7.2와
+0

기본 생성자가없는 무언가를 작성할 수는 있지만 항상 각 테이크 구조가 추가 인수를 기억하도록 요구하는 것이 약간의 부담이라는 것을 알게되었습니다. 제 취향에 너무 부담이됩니다. . 명백한 템플릿 인자로도 괜찮습니다.'std :: hash' 전문은 여전히 ​​가장 좋은 방법입니다 :-) –

+0

* 사용자 정의 유형 :-) 더 심각하게, 나는 우리가 그들을 때리기를 바란다. 이미 클래스에'char * '가 들어있는 스테이지의 손목에! –

+0

흠 ... '해시'전문화가 ADL을 통해 어떻게 방해되는지 보여주는 예가 있습니까? 내 말은, 그럴듯 해 보이지만 문제가 생길 때가 있습니다. –