pqn*_*net 5 c++ hash templates c++11 stdhash
我已经定义了这个模板类结构:
template<typename T> struct Outer {
struct Inner { /* ...some stuff... */ };
};
Run Code Online (Sandbox Code Playgroud)
我想将Inner对象放入一个unordered_map(实际上,不是直接将它们而是它们的容器,因此直接在模板参数上指定散列对象的方法unordered_map不是一个好主意),因此我想hash为这些项目专门化类。
这将不起作用,因为编译器无法与Outer<T>::Inner实例化时指定的类型匹配hash:
namespace std {
template<typename T> struct hash<typename Outer<T>::Inner > {
size_t operator ()( typename Outer<T>::Inner const & obj )
{ /* ...some stuff... */ }
};
};
Run Code Online (Sandbox Code Playgroud)
有谁知道这个问题的解决方案?
您显然是正确的,这将不起作用,因为编译器无法匹配基于此类依赖类型的模板特化(例如,Inner 可能是嵌套的 typedef,那么编译器将如何区分该类型来自 Outer 中的嵌套 typedef,还是来自其他地方?不能,也无法判断)。
有多种解决方案。
首先,您可以将 Inner 类移到 Outer 类的外部(并在需要时让它们成为朋友)。您还可以根据上下文将其移动到“详细信息”名称空间或以多种其他方式隐藏它。人们避免这种嵌套的“内部”类的情况并不少见,因为它们会导致许多这样的问题,一些较旧的编译器甚至根本无法接受此类嵌套类。将这些嵌套类移出外部类通常是更好的做法。就实际代码而言,您可以这样做:
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> > {
// ..
};
};
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是定义您自己的散列类,您可以将其提供给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;
};
Run Code Online (Sandbox Code Playgroud)
最后,还有另一个我能想到的解决方案,就像第一个解决方案一样,具有专门化std::hash类模板的优势。但是,这个解决方案有点复杂,它涉及将您的内部类包装到外部类模板中,如下所示:
template <typename T>
struct InnerWrapper {
typedef typename Outer<T>::Inner value_type;
value_type data;
};
Run Code Online (Sandbox Code Playgroud)
然后创建专业化std::hash< InnerWrapper<T> >。这个解决方案的真正优点是不干扰现有的 Outer 类的实现,但unordered_map在这种情况下创建一个意味着映射必须包含(直接或间接)InnerWrapper 对象,而不是直接存储 Inner 对象。此外,您应该注意到,通过在嵌套类中实现与 Outer 更紧密集成的 Inner 的一些功能,并在外部实现 Inner 的更多“公共”功能,可以将此解决方案与第一个解决方案混合使用类,从而避免了友谊关系并允许更紧密的外部-内部集成,同时留下一个干净的面向用户的类来访问内部的功能。
| 归档时间: |
|
| 查看次数: |
685 次 |
| 最近记录: |