在模板函数中,如果输入的类型是枚举类,如何使用 std::underlying_type ?

问题描述 投票:0回答:3

我有一段代码返回给定数字的某些位的值(我也使用 static_cast 将枚举类也算作数字)。

template<typename Type>
bool get_bits(Type input, uint8_t offset, uint8_t n, Type* destination)
{
    if (offset + n> sizeof(Type) * 8)
        return false;

    Type bitmask = 0;

    for (int i = 0; i < n; ++i)
        bitmask |= (1 << i);

    *destination = static_cast<Type>(input >> offset & bitmask);
    return true;
}

此函数尝试返回从

n
开始的
input
offset
位的值。它对于整数类型工作得很好,但是当我尝试将它与枚举类一起使用时,编译失败。我尝试使用 std::underlying_type 然后它适用于枚举类,但不适用于整数类型:|。我怎样才能将它用于他们两个?我的意思是,如果类型是枚举类,我想将输入转换为其
underlying_type
,执行一些按位运算,然后将结果(使用
static_cast
)存储到目的地。但这些转换不应该对没有underlying_type的整型进行。

c++ templates sfinae static-cast enum-class
3个回答
5
投票

如果您经常需要它,可以在

std::underlying_type
上编写适配器。像这样的东西

namespace detail {
  template<typename T, bool = std::is_enum<T>::value>
  struct underlying_type { using type = T; };

  template<typename T>
  struct underlying_type<T, true> : ::std::underlying_type<T> {};
}

当您使用

detail::underlying_type<T>
时,默认参数也会发生替换。当提供的类型不是枚举时,主模板与参数匹配(隐式),并且公开的
type
T

当提供的类型是枚举时(并且只有在这种情况下),才会使用特化。它所做的只是转向标准特征。


4
投票

您可以使用 SFINAE 来拆分枚举类实现:

template <typename Type,
          typename = std::enable_if_t<std::is_enum_v<Type>>>
bool get_bits(Type input, uint8_t offset, uint8_t n, Type* destination) {
    // enum-class implementation
}

及整体实施:

template <typename Type,
          typename = std::enable_if_t<std::is_integral_v<Type>>>
bool get_bits(Type input, uint8_t offset, uint8_t n, Type* destination) {
    // integral implementation
}

以上是C++17版本。

对于 C++11,你会得到类似的东西:

template <typename Type,
          typename std::enable_if<std::is_enum<Type>::value>::type* = nullptr>
bool get_bits(Type input, uint8_t offset, uint8_t n, Type* destination) {
    // enum-class implementation
}

template <typename Type,
          typename std::enable_if<std::is_integral<Type>::value>::type* = nullptr>
bool get_bits(Type input, uint8_t offset, uint8_t n, Type* destination) {
    // integral implementation
}

0
投票

已接受的答案有一个更短、更清晰的版本。在 C++17 中:

using maybe_underlying_type = std::conditional_t<std::is_enum_v<Type>, std::underlying_type_t<Type>, Type>;

只要您需要在函数内优雅地应用

std::underlying_type
,您就可以使用它。

在 C++11 中,你必须更详细一点:

using maybe_underlying_type = typename std::conditional<std::is_enum<Type>::value, std::underlying_type_t<Type>, Type>::type;
© www.soinside.com 2019 - 2024. All rights reserved.