我正在为我的对象编写一个哈希函数。由于Generic Hash function for all STL-containers,我已经可以散列容器并组合散列。但我的课程也有枚举。当然我可以为每个枚举创建一个哈希函数,但这似乎不是一个好主意。是否可以为std::hash
创建一些通用规范,以便它可以应用于每个枚举?类似的东西,使用std::enable_if
和std::is_enum
namespace std {
template <class E>
class hash<typename std::enable_if<std::is_enum<E>::value, E>::type> {
public:
size_t operator()( const E& e ) const {
return std::hash<std::underlying_type<E>::type>()( e );
}
};
};
PS。此代码无法编译
error: template parameters not used in partial specialization:
error: ‘E’
答案 0 :(得分:11)
无法推断出您的E
参数,因为编译器无法知道您的enable_if<...>::type
最终再次表示E
(事实上,有一些专业化的设计要求那样做!)。它被称为E
的“非推断上下文”。
如果hash
只有一个参数,那么SFINAE就没有办法(我知道)你的部分专业化了。
答案 1 :(得分:4)
如果您愿意使用宏,则可以在枚举声明旁边转储正确的std :: hash特化。
否则,我发现轻松散列枚举值的唯一方法是概括散列类型:
struct enum_hash
{
template <typename T>
inline
typename std::enable_if<std::is_enum<T>::value, std::size_t>::type
operator ()(T const value) const
{
return static_cast<std::size_t>(value);
}
};
以这种方式使用它:
enum class E { a, b, c };
std::unordered_map<E, std:string, enum_hash> map;
map[E::a] = "a";
答案 2 :(得分:3)
通过将特化失败移出模板参数列表,可以实现E的参数推导。例如,您可以使用声明:
namespace std {
template<class E>class hash {
using sfinae = typename std::enable_if<std::is_enum<E>::value, E>::type;
public:
size_t operator()(const E&e) const {
return std::hash<typename std::underlying_type<E>::type>()(e);
}
};
};
(我通常使用类型名称sfinae
,以便记住它为什么存在。)
演示代码:
#include <functional>
namespace std {
template<class E>class hash {
using sfinae = typename std::enable_if<std::is_enum<E>::value, E>::type;
public:
size_t operator()(const E&e) const {
return std::hash<typename std::underlying_type<E>::type>()(e);
}
};
};
enum foo { BAR, BAZ };
class quux {};
int main() {
// Compiles.
std::hash<foo>foo_hash;
// Gives a compile-time error: no type named ‘type’ in ‘struct
// std::enable_if<false, quux>’.
std::hash<quux>quux_hash;
return 0;
}
答案 3 :(得分:2)
标准禁止您尝试做的事情。
[namespace.std]
如果添加声明或者C ++程序的行为是未定义的 定义命名空间std或命名空间std中的命名空间 除非另有说明。
程序可以为任何程序添加模板专业化 标准库模板到命名空间std只有声明 取决于用户定义的类型和专业化符合 原始模板的标准库要求,而不是 明确禁止。
所以你当然可以在这些答案中追求一些想法,但你不能称之为std :: hash。定义自己的'enum_hash'模板似乎是一个好主意。