C++ 计算位以在编译时表示枚举

C++ 计算位以在编译时表示枚举,c++,enums,bit-fields,C++,Enums,Bit Fields,我需要压缩我的结构以节省内存,我得到了如下数据结构: enum class Foo { F1, F2, F3, FEnd, }; struct Bar { bool b: 1; Foo foo : 2; // Foo has 3 elements, 2 bits can represent them }; struct Bar { bool b: 1; Foo foo : bits(static_cast<int>(Foo::FEnd) - 1);

我需要压缩我的结构以节省内存,我得到了如下数据结构:

enum class Foo {
  F1,
  F2,
  F3,
  FEnd,
};

struct Bar {
  bool b: 1;
  Foo foo : 2; // Foo has 3 elements, 2 bits can represent them
};
struct Bar {
  bool b: 1;
  Foo foo : bits(static_cast<int>(Foo::FEnd) - 1);
};
而且
Foo
的元素仍有增加的可能,因此我不想硬编码
Foo-Foo:2
并在每次
Foo
添加元素时对其进行更改

目前我得到了一个解决方案:
constexpr static int I=32-uuu builtin_clz(static_cast(Foo::FEnd))

有什么建议吗?

< P>由于C++标准没有提及<代码> CONTXPRP</COD>数学库,其解决方案是:

constexpr uint64_t bits(const uint64_t x) {
  int i = 64;
  uint64_t mask = 0x8000000000000000;
  while (i > 0) {
    if ((mask & x) != 0) return i;
    i--;
    mask /= 2; // do not use >>, which is a non-constexpr in standard.
  }
  return 1;
}
然后示例代码如下所示:

enum class Foo {
  F1,
  F2,
  F3,
  FEnd,
};

struct Bar {
  bool b: 1;
  Foo foo : 2; // Foo has 3 elements, 2 bits can represent them
};
struct Bar {
  bool b: 1;
  Foo foo : bits(static_cast<int>(Foo::FEnd) - 1);
};

Edit2:正如@uncillation_mark所提到的,
std::log2(x)
返回
double
,并可能导致错误,这取决于输入,因此建议定制
constepr
函数,即使使用GCC也要进行检查。

RAM是便宜的。省钱很少值得这么麻烦。我不确定到底是什么问题。您可以在
constepr
函数中简单地实现
clz(x)
,有关算法,请参见示例。这不是足够的吗?C++中的枚举不是不可变的吗?为什么您担心有人在
Foo
中添加更多的枚举字段,这会改变每个枚举值的大小吗?@smac89问题是,当程序员向枚举定义中添加元素时,位字段的大小很可能会自动更正,以避免出现错误。@U mark我认为您是对的,我应该写我自己的
constexpr int clz(x)
,因为它是
std::log2
打字错误?因为这不是特定于GCC的,而是一个标准函数。但是,它返回一个
双精度
,因此它不能用作位字段的大小。Hi@unglish\u mark,我在答案中添加了GCC实现,返回类型是一个打字错误。我已经修好了。在我的回答中编写的代码在我这方面很好(gcc 7.4.0)是的,显式转换为
int
是可以编译的,并且可能可以工作,但它只在
enum
的大小在
double
中可以精确表示,并且只要
std::log2
不会对结果引入任何错误时才起作用,因为它是一个浮点函数,所以可以这样做。如果结果是完全可表示的,那么GCC实现可能不会引入任何错误,但没有保证。这就是为什么C++20中会引入正确处理整数的
std::log2p1
。同意,这就是为什么在这种情况下,即使我使用了GCC,我也会使用更多检查来定制我的函数,而不是使用
std::log2
。我将更新我的答案以警告这一点。