您显然是对的,这不起作用,因为编译器无法匹配基于此类依赖类型的模板专业化(例如,Inner 可能是嵌套的 typedef,那么编译器如何能够区分该类型之间的差异来自 Outer 中的嵌套 typedef,还是来自其他地方?它不能,不可能分辨)。
有多种解决方案。
首先,您可以将内部类移到外部类的外部(如果需要,并让他们成为朋友)。您还可以根据您的上下文将其移至“详细”命名空间或以多种其他方式隐藏它。人们避免此类嵌套“内部”类的情况并不少见,因为它们可能会导致许多类似的问题,并且一些较旧的编译器甚至在接受此类嵌套类时存在问题。通常更好的做法是将这些嵌套类移出外部类。就实际代码而言,您可以这样做:
template <typename T>
struct Outer; // forward-decl.
namespace detail {
template <typename T>
struct Outer_Inner {
friend class Outer<T>; // Optional
// ....
};
};
template <typename T>
struct Outer {
typedef detail::Outer_Inner<T> Inner;
friend class detail::Outer_Inner<T>; // Optional
// ...
};
namespace std {
template<typename T>
struct hash< detail::Outer_Inner<T> > {
// ..
};
};
另一个解决方案是定义您自己的哈希类,您可以将其提供给unordered_set
。像这样:
template <typename T>
struct Outer {
struct Inner {
//..
};
struct InnerHash {
typedef Inner argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& s) const {
return /* some hashing code */;
};
};
// ...
// An example unordered-set member:
std::unordered_set<Inner, InnerHash> m_set;
};
最后,我能想到的还有另一个解决方案,与第一个解决方案一样,它的优点是专门化std::hash
类模板。然而,这个解决方案有点复杂,它涉及将内部类包装到外部类模板中,如下所示:
template <typename T>
struct InnerWrapper {
typedef typename Outer<T>::Inner value_type;
value_type data;
};
然后创建专业std::hash< InnerWrapper<T> >
。该解决方案实际上仅具有不侵入外部类的现有实现的优点,但创建了一个unordered_map
在这种情况下意味着映射必须(直接或间接)包含 InnerWrapper 对象,而不是直接存储 Inner 对象。另外,您应该注意到,该解决方案可以与第一个解决方案混合,方法是将 Inner 的一些功能与在嵌套类中实现的 Outer 更紧密地集成,并在外部实现 Inner 的更多“公共”功能类,从而避免了友谊关系并允许更紧密的外部-内部集成,同时留下一个干净的面向用户的类来访问内部的功能。