从类型到相同类型的“转换”导致错误

时间:2015-09-08 14:31:51

标签: c++ c++11 metaprogramming template-meta-programming

我有一个模板函数,其中枚举类型转换为其基础类型,工作正常,但我写了一个重载应该采用整数并返回自身,它给我一个错误,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

2 个答案:

答案 0 :(得分:4)

std::underlying_type<TT>::type正在std::enable_if中进行评估,即使std::is_enum<TT>::valuefalse,因为false不是错误。由于正在评估非枚举类型,因此导致错误。如果我们将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

中工作

答案 1 :(得分: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的{​​{1}}定义被请求std::enable_if<B,T>::type }返回。

DEMO