如何覆盖类中定义的枚举的std :: hash?

Tal*_*lin 10 c++ stl unordered-set c++11

我有一个在类中定义的枚举类型,我想创建这些对象的unordered_set作为类的成员:

#include <unordered_set>

class Foo {
public:
  enum Bar {
    SOME_VALUE
  };

  // Error: implicit instantiation of std::hash
  std::unordered_set<Bar> getValues() const {
     return _values;
  }

private:
  std::unordered_set<Bar> _values;
};
Run Code Online (Sandbox Code Playgroud)

现在,我知道明显的答案是在unordered_set中添加自定义哈希函数:

std::unordered_set<Bar, BarHasher>
Run Code Online (Sandbox Code Playgroud)

但是,我想知道的是,是否有一种方法可以为bar枚举专门化std :: hash,这样任何使用unordered_map的人都会自动获得散列行为.

这适用于所有其他数据类型,但不适用于枚举 - 因为枚举不能向前声明.

为了使它工作,我必须在枚举定义之后放置std :: hash的定义,但是在第一次使用之前,这意味着我必须将它放在类主体的中间,这赢得了不行.

Nev*_*ore 4

然而,我想知道是否有一种方法可以专门用于 Bar 枚举的 std::hash ,以便任何使用 unordered_map 的人都能自动获得哈希行为。

没有奇迹,所以任何人std::hash只有在专业化之后才会使用专业化。std::hash由于您无法在另一个类中专门化类,并且您的枚举是嵌套的,因此在类内部使用会出现问题。正如您所指出的,枚举不能向前声明。std::hash因此,有唯一的解决方案(无需创建基类或“取消嵌套”枚举)在类内部使用专门化:通过引用聚合/声明并在std::hash专门化后在外部使用。

#include <iostream>
#include <unordered_set>
#include <memory>

struct A {

    enum E {
        first, second
    };

    A();

    std::unique_ptr< std::unordered_set<E> > s_; //!< Here is
};

namespace std {

template<>
class hash<A::E> {
public:
    std::size_t operator()(A::E const& key) const noexcept {
        std::cout << "hash< A::E >::operator()" << std::endl;
        return key;
    }

};

}

A::A()
    : s_(new std::unordered_set<E>)
{ }

int main(void) {
    A a;
    a.s_->insert(A::first);

    std::unordered_set< A::E > s;
    s.insert(A::second);
}
Run Code Online (Sandbox Code Playgroud)

打印出来

哈希< A::E >::operator()
哈希< A::E >::operator()

因此,在课堂之外A每个人都可以使用A::Ewith std::hash,在课堂内部我们也可以使用A::Ewith std::hash。另外,如果您不想std::unordered_set通过引用进行聚合,您可以实现自定义哈希器仅供内部使用(然后将std::hash调用转发给它)。