std :: conditional vs std :: enable_if

Som*_*ken 14 c++ c++14

我有一个哈希函数可以采用任何对象类型并哈希它,它在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);
}
Run Code Online (Sandbox Code Playgroud)

这工作正常.然后我尝试将它全部放入一个函数中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);
}
Run Code Online (Sandbox Code Playgroud)

主要:

enum test
{
    TEST = 2
};

int main() {
    Hash<test>(TEST);
    Hash<int>(5);
    std::cin.get();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

然而,这给了我一个错误:

/ usr/include/c ++/5/type_traits:2190:38:错误:'int'不是枚举类型typedef __underlying_type(_Tp)类型;

我确实理解错误,但我不明白为什么,我认为std::conditional会阻止这些编译时错误,因为<int>使用std::hash<T>而不是 std::hash<typename std::underlying_type<T>::type>在编译时.

我在这里做错了什么,有没有办法合并这2个功能?

Tar*_*ama 13

std::underlying_type如果模板参数不是枚举,并且两个分支都std::conditional需要有效,那么问题就是格式不正确.

一种可能性是制作一个safe_underlying_type特征,void如果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>; 
};
Run Code Online (Sandbox Code Playgroud)

或者你可以写一个特征来获得你想要的哈希类型:

template <typename T, typename = typename std::is_enum<T>::type>
struct hash_type {
    using type = std::hash<T>;
};

template <typename T>
struct hash_type<T, std::true_type> {
    using type = std::hash<std::underlying_type_t<T>>;  
};
Run Code Online (Sandbox Code Playgroud)


T.C*_*.C. 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>;
Run Code Online (Sandbox Code Playgroud)

此外,std::hashLWG 2148以来,应该原生支持枚举.