std :: conditional vs std :: enable_if

时间:2016-02-02 11:55:35

标签: 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);
}

这很好用。 然后我尝试用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>在编译时。

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

4 个答案:

答案 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只会让你更难阅读。