2014-02-20 1 views
2

해시 할 수있는 클래스가 추상 기본 클래스 Hashable입니다. 이제 std::hashHashable에서 파생 된 모든 클래스로 확장하려고합니다.파생 클래스에 대한 표준화 표준 :: 해시

다음 코드는 정확히 수행해야합니다.

#include <functional> 
#include <type_traits> 
#include <iostream> 

class Hashable { 
public: 
    virtual ~Hashable() {} 
    virtual std::size_t Hash() const =0; 
}; 

class Derived : public Hashable { 
public: 
    std::size_t Hash() const { 
     return 0; 
    } 
}; 

// Specialization of std::hash to operate on Hashable or any class derived from 
// Hashable. 
namespace std { 
template<class C> 
struct hash { 
    typename std::enable_if<std::is_base_of<Hashable, C>::value, std::size_t>::type 
    operator()(const C& object) const { 
    return object.Hash(); 
    } 
}; 
} 

int main(int, char**) { 
    std::hash<Derived> hasher; 
    Derived d; 
    std::cout << hasher(d) << std::endl; 

    return 0; 
} 

GCC 4.8.1 예상대로 위의 코드는 정확히 작동하지만, 내가 GCC 4.7.2로 컴파일 할 때, 나는 다음과 같은 얻을 :

$ g++ -std=c++11 -o test test_hash.cpp 
test_hash.cpp:22:8: error: redefinition of ‘struct std::hash<_Tp>’ 
In file included from /usr/include/c++/4.7/functional:59:0, 
       from test_hash.cpp:1: 
/usr/include/c++/4.7/bits/functional_hash.h:58:12: error: previous definition of ‘struct std::hash<_Tp>’ 
/usr/include/c++/4.7/bits/functional_hash.h: In instantiation of ‘struct std::hash<Derived>’: 
test_hash.cpp:31:24: required from here 
/usr/include/c++/4.7/bits/functional_hash.h:60:7: error: static assertion failed: std::hash is not specialized for this type 

는 사람이 생각할 수 std::hash의 전문화는 Hashable에서 gcc 4.7.2로 파생 된 모든 클래스에서 작동합니까?

+1

어를 더 그 코드가 손상되었습니다. 'std'에 새로운 템플릿을 선언 할 권한이 없습니다. 기존 템플릿의 전문화는 특정 조건에서만 작성할 수 있습니다. 당신이 가지고있는 것은 전문화가 아닙니다 –

+2

표준 네임 스페이스에서 여러분이 할 수 있고 허용되지 않은 규칙을 무시하더라도 클래스는 어떤 컨텍스트에서도 허용되지 않는 재정의입니다. 두 정의가 일치하기 때문에 모호합니다. 당신은 각 타입을 위해 또는'Hashable'을 위해서만 전문화해야하고 그것의 파생 된 타입 모두를 위해'std :: hash '을 사용하면됩니다. 이것이 내가 adl을 통해 함수가 아니라 템플릿과 같은 형질을 싫어하는 이유입니다. – John5342

+0

의견을 보내 주셔서 감사합니다. 나는 나의 해결책이 상당히 정결하지 못하다는 것을 의심했고 실제로 gcc 4.8.1에서 전혀 효과가 없다는 것에 놀랐다. 각 파생 된 클래스에 대해 별도의 전문화를 작성하기로 결정했습니다. – Flecto

답변

1

내가하고 싶은 일을하는 적절한 방법이없는 것처럼 보입니다. 나는 다음과 같은 매크로를 사용하여, 단지 각 파생 클래스에 대해 별도의 전문을 쓰기로했다 없었다 :

// macro to conveniently define specialization for a class derived from Hashable 
#define DEFINE_STD_HASH_SPECIALIZATION(hashable)        \ 
namespace std {                \ 
template<>                  \ 
struct hash<hashable> {              \ 
    std::size_t operator()(const hashable& object) const {      \ 
    return object.Hash();              \ 
    }                   \ 
};                    \ 
} 

다음

// specialization of std::hash for Derived 
DEFINE_STD_HASH_SPECIALIZATION(Derived); 
관련 문제