我有一个模板类Baz
,其中包含一个嵌套的类Sub
。我想通过专门化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’
更新
我真正想要做的是实现一个容器,它支持稳定的引用(不是在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 :(得分:4)
只需将Reference类从Container中拉出来。
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>>;
}
答案 1 :(得分:2)
这个问题的答案是,你要做的事情根本不可能做到。编译器无法弄清楚外部类包含哪个子类型。考虑原因:
struct outer1 { typedef int Sub; };
struct outer2 { typedef int Sub; };
编译器如何在获得Sub时想出哪个外部?这不可以。没有办法实现这一点。
在你的情况下,尽管非常困难,可以远程实现IFF Sub依赖于T.但这需要编译器知道Sub来自哪里而它不会。
所以你根本做不到这一点。没办法,没办法。
如果你需要一些通用的方法来为你的类型找到一个哈希函数,那么你需要创建一个元函数get_hash。它可以默认查找“hash_type”内部typedef,并为标准哈希重写。很多打字......
或者,将Sub作为自己的模板放在包含的类之外,并在那里使用typedef而不是内部类。然后,您可以在模板上专门化哈希值。
否则,只需将哈希函数参数所需的哈希值提供给您正在使用的模板。
答案 2 :(得分: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
的第三个模板参数)。