如何覆盖类中定义的enum的std::hash
How to override std::hash for an enum defined inside a class?
我已经在一个类中定义了一个枚举类型,我想创建这些对象的一个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;
};
现在,我知道最明显的答案是向unordered_set添加一个自定义哈希函数:
std::unordered_set<Bar, BarHasher>
然而,我想知道的是,是否有一种方法可以为Bar枚举专门化std::hash,以便任何使用unordered_map的人都能自动获得散列行为。
这适用于所有其他数据类型,但不包括枚举-因为枚举不能向前声明。
为了使它工作,我必须把std::hash的定义放在enum定义之后,但在第一次使用之前,这意味着我必须把它放在类体的中间,这是行不通的。
然而,我想知道的是,是否有一种方法可以为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);
}
打印出
hash<答::E>::操作符()
hash<答::E>::操作符()
所以,在A
类之外,每个人都可以使用A::E
和std::hash
,以及在类内部,我们也使用A::E
和std::hash
。此外,如果您不想通过引用聚合std::unordered_set
,您可以实现自定义散列仅供内部使用(然后转发std::hash
对它的调用)。
一种可能是将枚举放入基类中。不幸的是,您必须为每个枚举成员提供using声明。解决这个问题的一种方法是使用有作用域的枚举(enum class Bar
),这需要像Foo::Bar::SOME_VALUE
一样使用,而不是Foo::SOME_VALUE
。这样做,您只需要using FooBase::Bar;
.
class FooBase {
public:
enum Bar {
SOME_VALUE
};
protected:
~FooBase() = default; //so can't be used polymorphically
};
//hash goes here
class Foo : FooBase {
public:
using FooBase::Bar;
using FooBase::SOME_VALUE;
...
你的问题似乎已经涵盖了所有的角度。
我想不出一个方法来做这件事。
概括地说,你只能改变现状:
- 使
enum
非嵌套(将其放在封闭的命名空间中),或者 - 像你的例子中那样显式地使用哈希函数。
- 在提升multi_index容器中,是否定义了"default index"?
- enum是C++中的宏变量还是整数变量
- #定义c-预处理器常量..我做错了什么
- 用C++中的一个变量定义一个常量
- 部分定义/别名模板模板参数
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- #为""定义宏;静态";针对不同的上下文
- 如何确保C++函数在定义之前声明(如override关键字)
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在命名空间中定义函数还是限定函数
- 此代码是否违反一个定义规则
- 如何理解c++中在命名空间内部定义的枚举类型enum
- c++ Visual Studio, 'vc_attributes::YesNoMaybe' : 'enum' 类型重定义错误
- 如何一致地定义可同时作为enum、int和string使用的选项列表
- 如何覆盖类中定义的enum的std::hash
- 是类实例之间共享的类中的' enum '定义,或为每个实例复制
- 从其他类的成员函数返回ENUM(在一个类中定义)
- 为什么非const、非int/enum静态数据成员必须在定义之外初始化?
- 从lib重新定义enum