2015-09-08 107 views
7

我有一个模板函数,其中枚举类型转换为其基础类型,但工作正常,但我写了一个重载应该采取一个整数并返回自身,它给我一个int不是枚举类型的错误。在我的模板中,这应该被过滤掉。哪里不对?从类型到相同类型的“转换”导致错误

这里是模板代码:

template <typename TT> 
    static constexpr auto get_value(TT t) 
    -> typename std::enable_if<!std::is_enum<TT>::value, TT>::type 
    { 
     return t; 
    } 

    template <typename TT> 
    static constexpr auto get_value(TT t) 
    -> typename std::enable_if<std::is_enum<TT>::value, typename std::underlying_type<TT>::type>::type 
    { 
     return (typename std::underlying_type<TT>::type)t; 
    } 

Demo

+1

我不知道'underlying_type'是SFINAE友好,但有一个[解决方法](http://coliru.stacked-crooked.com/a/e7f1dd3b75c8d9c2)为 –

+0

什么?我看到它有效,但是这里发生了什么,使它起作用了?为什么SFINAE友好的'underlying_type'不会? – Adrian

+1

“std :: underlying_type :: type”的实例化被推迟,所以'enable_if'可能首先失败。 * * SFINAE友好的*我的意思是任何替换失败都只发生在紧接着的上下文中(如果它发生在'underlying_type'本身内部,它不是SFINAE友好的)。 –

回答

4

std::underlying_type<TT>::typestd::enable_if即使std::is_enum<TT>::valuefalsefalse是不是一个错误被评估。由于正在评估非枚举类型,因此会导致错误。如果我们将SFINAE移入模板参数中,我们可以得到所需的重载并仍然返回正确的类型。

template <typename TT, typename std::enable_if<!std::is_enum<TT>::value, TT>::type* = nullptr> 
static constexpr auto get_value(TT t) -> TT 
{ 
    return t; 
} 

template <typename TT, typename std::enable_if<std::is_enum<TT>::value>::type* = nullptr> 
static constexpr auto get_value(TT t) -> typename std::underlying_type<TT>::type 
{ 
    return (typename std::underlying_type<TT>::type)t; 
} 

你可以看到它在这个Live Example

+0

因此,为了确保我正确理解这一点,第二个模板参数是一个类型为'void *'的未命名参数,如果is /不是枚举类型(取决于我想要的)导致创建,而非实体if不是我想要的,然后会被拒绝? – Adrian

+0

@Adrian如果'std :: enable_if'成功'type'是void,那么我们可以为SFINAE设置一个类型为'nullptr'的指针 – NathanOliver

+0

@dyp我编辑了答案。它应该解决现在的实际原因。 – NathanOliver

4

工作正常,尝试实例std::underlying_type<T>T这不是一个枚举类型,你违反了该标准的模板参数T规定要求:

§20.10.7.6 [meta.trans.other] /表57:

 Template   |   Condition   |  Comments 
------------------------+---------------------------+----------------------- 
template <class T>  | T shall be an enumeration | The member typedef 
struct underlying_type; | type (7.2)    | type shall name 
         |       | the underlying type 
         |       | of T. 

这里的,如果一个人不喜欢任何额外的模板参数的另一种方法:

template <typename TT> 
static constexpr auto get_value(TT t) 
    -> typename std::enable_if<!std::is_enum<TT>::value, TT>::type 
{ 
    return t; 
} 

template <typename TT> 
static constexpr auto get_value(TT t) 
    -> typename std::enable_if<std::is_enum<TT>::value 
          , std::underlying_type<TT> 
       >::type::type 
{ 
    return (typename std::underlying_type<TT>::type)t; 
} 

这样,std::underlying_type<TT>实例化被推迟,直到std::enable_if条件值为true,因为嵌套type定义请求为什么std::enable_if<B,T>::type返回。

DEMO

+0

因此,只有当您获得'std :: underlying_type :: type'类型而不需要'std :: underlying_type '本身时才需要该需求?这是为什么? – Adrian

+1

@Adrian'std :: underlying_type '仅在用作类型模板参数时未实例化 –