如何将固定大小的枚举值设置为其最大可能值?

How to set enum val of fixed size to its max possible value?

这可能很简单,但我没有做对。我有一个“位掩码”枚举,它的值 all 表示所有位都已设置。但是,我无法使用 ~0 翻转所有位。出现以下错误:

<source>:11:16: error: enumerator value '-1' is outside the range of underlying type 'uint_fast8_t' {aka 'unsigned char'}
   11 |         all = ~0x0,
      |             

这很奇怪,因为它实际上应该适合 uint8_t 不?这是我的代码 (godbolt):

#include <iostream>

int main()
{
    enum mask_t : uint_fast8_t {
        first = 0x1,
        second = 0x2,
        all = ~0x0,
    } mask;

    mask = all;
}

您需要将具有类型 int 和负值的表达式 ~0x0 转换为类型 uint_fast8_t,例如

all = static_cast<uint_fast8_t>( ~0x0 ),

为什么表达式的类型是 int?因为整数文字 0x0 具有类型 int 并且运算符 ~ 不会更改表达式的类型。

来自 C++ 标准

2 The type of an integer literal is the first of the corresponding list in Table 5 in which its value can be represented.

并且 int 类型的对象可以表示文字 0x0

这是一个演示程序。

#include <iostream>
#include <iomanip>
#include <type_traits>

int main()
{
        
    std::cout << std::boolalpha << std::is_same_v<int, decltype( 0x0 )> << '\n';
}

程序输出为

true

另一种方法就是写

all = 0xff,

你可以借助一些meta-programming技巧获得最大值

#include <limits>
#include <type_traits>
#include <cstdint>

enum mask_t : uint_fast8_t {
  first = 0x1,
  second = 0x2,
  all = std::numeric_limits<std::underlying_type_t<mask_t>>::max()
} mask;

Demo

默认情况下,0x0 的类型为 int。因此,如果您尝试翻转所有位,您将得到 -1 无法分配给您的枚举定义的类型。

即使您为该文字值使用后缀,例如 u。表示字面值是无符号类型。如 ~0x0u。您将获得 unsigned int 类型的最大值。这超出了您正在使用的 8 位整数类型的范围。所以这也不管用。

所以你需要先告诉语言你希望文字值是你需要的类型。这可以通过 static_cast 实现,如其他答案所示:

static_cast<uint_fast8_t>( ~0x0 )

但是,如果您决定稍后更改枚举的类型,使用硬编码类型和值有时会妨碍您。所以如果你有可用的 c++14。您可以使用 std::underlying_type type-trait 并制作一个通用实用程序,例如:

template < class T > constexpr std::underlying_type_t< T > enum_max_v = ~static_cast< std::underlying_type_t< T > >(0);
// If you have c++17 available with the inline keyword
// template < class T > inline constexpr std::underlying_type_t< T > enum_max_v = ~static_cast< std::underlying_type_t< T > >(0);

然后像这样使用:

enum mask_t : uint_fast8_t {
    first = 0x1,
    second = 0x2,
    all = enum_max_v< mask_t >,
} mask;

现在你不必关心枚举的底层类型了。

如果您想要正确的值而不是依赖翻转位,您甚至可以使用 std::numeric_limits

template < class T > constexpr std::underlying_type_t< T > enum_max_v = std::numeric_limits< std::underlying_type_t< T > >::max();

天空无极限。