2012-05-05 1 views
5

템플릿 클래스 Baz에 중첩 클래스 Sub이 있습니다. std :: hash를 전문화하여이 서브 클래스의 해시 함수를 정의하고 싶습니다. 그러나, 그것은 작동하지 않는 것 같습니다.템플릿 클래스의 중첩 클래스에 대한 std :: hash 특수화

#include <functional> 

struct Foo { 
    struct Sub { 
    }; 
}; 

template <class T> 
struct Bar { 
}; 

template <class T> 
struct Baz { 
    struct Sub { 
     int x; 
    }; 
}; 

// declare hash for Foo::Sub - all right 
namespace std { 
    template <> 
    struct hash<Foo::Sub>; 
} 

// declare hash for Bar<T> - all right 
namespace std { 
    template <class T> 
    struct hash< Bar<T> >; 
} 

// declare hash function for Baz<T>::Sub - doesn't work! 
namespace std { 
    template <class T> 
    struct hash< Baz<T>::Sub >; 
} 

// Adding typename produces a different error. 
namespace std { 
    template <class T> 
    struct hash< typename Baz<T>::Sub >; 
} 

GCC 4.5.3 불평 :

$ g++ -std=c++0x -c hash.cpp 
hash.cpp:34:30: error: type/value mismatch at argument 1 in template parameter list for ‘template<class _Tp> struct std::hash’ 
hash.cpp:34:30: error: expected a type, got ‘Baz<T>::Sub’ 
hash.cpp:40:12: error: template parameters not used in partial specialization: 
hash.cpp:40:12: error:   ‘T’ 

UPDATE

내가 정말 할 노력하고있어 것이 아니라 C 안정 참조를 (지원하는 컨테이너를 구현하는 것입니다 ++ 감각)을 그 안에있는 요소들에 적용합니다. 사용자가 이러한 참조를 std::unordered_set 및 그 유사 항목에 삽입하고 기존 요소를 효율적으로 액세스하거나 수정하는 데 사용하도록 허용하려고합니다. 다음은 실물 모형입니다. 구현중인 컨테이너가 아닙니다. 문제는 참조 유형에 대한 해시 함수를 정의하는 데 있습니다.

template <class T> 
class Container { 
public: 
    class Reference { 
    public: 
     // operator==, operator!=, operator< ...., isNull() 
    private: 
     size_t index; // index into m_entries (or could be anything else) 
     // possibly more stuff 
    }; 

    Reference insert (const T &value); 
    Reference find (const T &value); 
    void remove (Reference r); 
    Reference first(); 
    Reference next (Reference prev); 

private: 
    struct Entry { T value, ... }; 

    std::vector<Entry> m_entries; 
}; 
+0

이의 쓰임새는 무엇입니까? 아마도 컨테이너에 명시적인 해시 함수를 지정하는 것이 더 쉬울까요? –

답변

2

이 질문에 대한 대답은 당신이하려는 일이 단순히 불가능하다는 것입니다. 컴파일러는 어떤 외부 클래스가 하위 유형을 포함하고 있는지 파악할 수 없습니다. 이유를 생각해보십시오 :

struct outer1 { typedef int Sub; }; 
struct outer2 { typedef int Sub; }; 

컴파일러는 Sub가 생길 때 원하는 외부를 어떻게 알 수 있습니까? 그럴 순 없어. 이 작업을 수행 할 수있는 방법은 없습니다.

IFF Sub를 T에 의존하여 도출 할 수는 있지만 원격으로 가능할 수도 있습니다.하지만 컴파일러는 Sub가 어디서 왔는지 알기 위해 컴파일러가 필요합니다.

이렇게하면 안됩니다. 안돼, 안돼.

유형에 대한 해시 함수를 찾는 일반적인 접근 방식이 필요한 경우 메타 기능 get_hash를 만들어야합니다. 기본적으로 "hash_type"내부 typedef를 찾고 표준 해시에 대해 재정의 할 수 있습니다. 많은 타이핑 ...

또는 포함하는 클래스에서 Sub를 자체 템플릿으로 지정하고 내부 클래스 대신 typedef를 지정합니다. 그런 다음 템플릿에서 해시를 전문화 할 수 있습니다.

그렇지 않으면 사용중인 템플릿에 해시 함수 매개 변수에 필요한 해시를 제공하십시오.

+0

네, 맞습니다. 이 예제에서 컴파일러가 'int'를 얻으면 사용할 해시를 알 수 없습니다. 그러나 필자는 예제에서 typedef를 사용하지 않고 다른 클래스의 별칭이 아닌 중첩 클래스를 사용합니다. 컴파일러가 Sub를 얻었을 때 이미 (내가 믿는다) 그것이 속한 부모 클래스를 알고있다. –

+0

@AmbrozBizjak - 그렇지 않습니다. 내부 클래스를 풀고 대신 typedef를 사용해야합니다. 네가 나를 믿지 않는다면 너는 벽에 머리를 때리는 데 많은 시간을 낭비하게 될거야. 정말로. C++은 당신이하려는 일을 지원하지 않을 것이며, 당신이 그것에 대해 어떻게 할 것인지를 지원하지 않을 것입니다. 나는 당신이 stackoverflow에 대해 비슷한 질문을 1000 개나 발견 할 것이고 그 대답은 항상 동일하다고 생각한다. –

+0

그래, 고마워. 고마워. 나는 수업을 바깥으로 옮겼다. 이제는 잘 돌아 간다. –

0

템플릿을 이와 같은 종속 형으로 전문화 할 수 없습니다. 나는 이와 같은 것을 시도 할 것이다.

struct yes {}; 

template <typename T> 
yes accept_baz_sub(typename Baz<T>::Sub&&); 
void accept_baz_sub(...); 

template <class T> 
struct is_baz_sub : std::is_same<decltype(accept_baz_sub(std::declval<T>())), yes> 
{}; 

template <typename BazSub> 
using CheckedBazSub = typename std::enable_if<is_baz_sub<BazSub>::value, BazSub>::type; 

namespace std { 
    template <class BazSub> 
    struct hash<CheckedBazSub<BazSub>>; 
} 

편집 : 이것은하지 않습니다 잘 작동, [temp.alias]에 §14.5.7.2 별칭 템플릿 이름이 추론되지 않습니다 따라.

또 다른 해법은 자신의 해시 함수 객체를 작성하고 컨테이너가이를 사용하게하는 것입니다 (예 : std::unordered_map의 세 번째 템플릿 매개 변수).

+0

"오류 : 부분 템플릿에서 기본 템플릿 인수를 사용할 수 없습니다." –

4

컨테이너에서 참조 클래스를 가져옵니다.

template <class Container> 
class Reference { 
public: 
    typedef typename Container::value_type value_type; // etc... 

    // operator==, operator!=, operator< ...., isNull() 
private: 
    size_t index; // index into m_entries (or could be anything else) 
    // possibly more stuff 
}; 

template <class T> 
class Container { 
public: 
    typedef ::Reference<Container> Reference; 
    friend class Reference; // If you cannot help it 

    typedef T value_type; 

    Reference insert (const T &value); 
    Reference find (const T &value); 
    void remove (Reference r); 
    Reference first(); 
    Reference next (Reference prev); 

private: 
    struct Entry { T value, ... }; 

    std::vector<Entry> m_entries; 
}; 

은 다음과 같이 전문화 :

namespace std { 
    template <typename Container> 
    struct hash<Reference<Container>>; 
} 
+0

고마워, 그게 내가 한거야; 그러나 나는 그가 그것을 처음 제안했기 때문에 Eddie의 대답을 받아 들였다. –

관련 문제