我有一个散列函数可以接受任何对象类型并对其进行散列,它在内部使用std::hash
。由于std::hash
不支持枚举类型,因此我创建了函数的重载,1用于使用std::underlying_type
的枚举,1用于其他类型:
template <typename T, typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
static std::size_t Hash(T const & t)
{
return std::hash<typename std::underlying_type<T>::type>()(t);
}
template <typename T, typename std::enable_if<!std::is_enum<T>::value>::type* = nullptr>
static std::size_t Hash(T const & t)
{
return std::hash<T>()(t);
}
这很好用。
然后我尝试用std::conditional
:
template <typename T>
static std::size_t Hash(T const & t)
{
typedef typename std::conditional<std::is_enum<T>::value, std::hash<typename std::underlying_type<T>::type>, std::hash<T>>::type Hasher;
return Hasher()(t);
}
主:
enum test
{
TEST = 2
};
int main() {
Hash<test>(TEST);
Hash<int>(5);
std::cin.get();
return 0;
}
然而,这给了我一个error:
/ usr / include / c ++ / 5 / type_traits:2190:38:错误:&#39; int&#39;不是枚举类型 typedef __underlying_type(_Tp)type;
我确实理解错误,但我不明白为什么,我认为std::conditional
会阻止这些编译时错误,因为<int>
使用std::hash<T>
代替std::hash<typename std::underlying_type<T>::type>
在编译时。
我在这里做错了什么,有没有办法合并这两个功能?
答案 0 :(得分:13)
问题是如果模板参数不是枚举,std::underlying_type
格式不正确,std::conditional
的两个分支都必须有效。
如果safe_underlying_type
不是枚举,则有一种可能性是制作只会返回void
的{{1}}特征:
T
或者你可以写一个特征来获得你想要的哈希类型:
template <typename T, typename = typename std::is_enum<T>::type>
struct safe_underlying_type {
using type = void;
};
template <typename T>
struct safe_underlying_type<T, std::true_type> {
using type = std::underlying_type_t<T>;
};
答案 1 :(得分:7)
如果您真的想使用conditional
,则需要推迟评估:
template<class T> struct identity { using type = T; };
using Hasher = std::hash<typename std::conditional<std::is_enum<T>::value,
std::underlying_type<T>,
identity<T>>::type::type>;
另外,std::hash
应该原生支持自LWG 2148以来的枚举。
答案 2 :(得分:2)
conditional
中使用的两种类型(分支)在编译时都需要很好地形成。
问题在于,当编译器解析std::conditional
本身时,语句typename std::underlying_type<T>::type
需要格式良好(并且不适用于int
)。它的结果并不重要,它还没有达到目的。
答案 3 :(得分:2)
typename std::underlying_type<T>::type
int
的格式不正确,但仍在编译时进行评估。这就是您收到此错误的原因。您已经使用std::enable_if
提供了解决方案,因此我不会在那里详细介绍。我认为这很好,使用std::conditional
只会让你更难阅读。