C++枚举是否可以大于 64 位?
Can a C++ enumeration be made bigger than 64 bits?
在我的实体组件系统中,我使用位掩码跟踪和查询每个实体具有哪些组件。
// Thanks to Shafik Yaghmour for the macro fix
#define BIT(x) (static_cast<std::uint64_t>(1) << x)
enum class components : std::uint64_t
{
foo = BIT( 0),
bar = BIT( 1),
// Many more omitted
baz = BIT(63)
};
// Operator | is used to build a mask of components. Some entities
// have dozens of components.
auto mask = components::foo | components::bar | components::baz
// Do something with the entity if it has the requisite components.
if ( entity->has_components( mask ) ) { ... }
我已经达到了枚举的 64 位限制。C++枚举(可移植)是否可以大于 64 位?
更新1:我知道std::bitset
,但我无法创建像auto mask = std::bitset<128>{ components::foo, components::baz }
这样的掩码,因为std::bitset
没有采用std::initializer_list
的构造函数。如果您的答案告诉我使用std::bitset
请演示此用法或类似用法。
更新2:我破解了一个函数来从std::initializer_list
创建std::bitset
:
enum class components : std::size_t
{
foo,
bar,
baz,
count
};
template< typename enumeration, std::size_t bit_count = static_cast< std::size_t >( enumeration::count ) >
std::bitset< bit_count > make_bitset(std::initializer_list< enumeration > list)
{
assert(list.size() <= bit_count);
std::bitset< bit_count > bs{};
for (const auto i : list)
{
bs.set(static_cast< std::size_t >(i));
}
return bs;
}
// Which can create the mask like so:
auto mask = make_bitset< components >( {components::foo, components::baz} );
正如其他人所指出的,存储必须是std::bitset
。但是如何将其与枚举接口呢?使用本答案中概述的运算符重载。枚举器只需要存储位索引号,这为您购买了更多的空间;)。
请注意,必须从移位操作中清除该代码,即:
flag_bits( t bit ) // implicit
{ this->set( static_cast< int >( bit ) ); }
http://ideone.com/CAU0xq
请注意,您当前的代码具有未定义的行为,整数文本1
在此处具有int类型:
#define BIT(x) (1 << x)
^
这在大多数现代系统上可能会32 bits
,因此根据Shift 运算符5.8
标准部分C++草案,移位32 bit
或更多是未定义的行为,该部分说:
如果右操作数为负数,或者大于或等于提升的左操作数的长度(以位为单位),则行为未定义。
解决此问题的方法是使用 static_cast 将1
转换为uint64_t:
#define BIT(x) (static_cast<std::uint64_t>(1) << x)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
或者正如Potatoswatter指出的那样,您可以使用保证64 bit
ULL
后缀。没有可移植的方式来使用比uint64_t更大的类型,一些编译器(如 gcc)提供128 bit
整数类型,但同样不可移植。
std::bitset 应该提供你需要的接口。可以使用 set 将任何位设置为任何值,并使用 test 来测试特定位的值。它提供二进制文件或应提供此功能的二进制文件:
auto mask = components::foo | components::baz
例如:
#include <bitset>
#include <iostream>
int main()
{
std::bitset<128> foo ;
std::bitset<128> baz ;
foo.set(66,true ) ;
baz.set(80,true ) ;
std::cout << foo << std::endl ;
std::cout << baz << std::endl ;
std::bitset<128> mask = foo | baz ;
std::cout << mask << std::endl ;
return 0;
}
使用std::bitset
.
附录:
在我写完上面的答案后,这个问题已经更新了,提到了std::bitset
和一些关于如何使用它的不好的想法,到目前为止有 13 次修订。
我没有预见到使用std::bitset
可能会有任何困难,对不起。因为这只是不引入不必要的复杂性,避免这样做的问题。例如,而不是现在建议的
#include <bitset>
enum class components : std::size_t
{
foo,
bar,
baz,
count
};
template< typename enumeration, std::size_t bit_count = static_cast< std::size_t >( enumeration::count ) >
std::bitset< bit_count > make_bitset(std::initializer_list< enumeration > list)
{
assert(list.size() <= bit_count);
std::bitset< bit_count > bs{};
for (const auto i : list)
{
bs.set(static_cast< std::size_t >(i));
}
return bs;
}
auto main() -> int
{
auto mask = make_bitset< components >( {components::foo, components::baz} );
}
只需做例如
#include <bitset>
namespace component {
using std::bitset;
enum Enum{ foo, bar, baz };
enum{ max = baz, count = max + 1 };
using Set = bitset<count>;
auto operator|( Set const s, Enum const v )
-> Set
{ return s | Set().set( v, true ); }
} // namespace component
auto main() -> int
{
auto const mask = component::Set() | component::foo | component::baz;
}
或者简单地说,没有句法加糖,
#include <bitset>
namespace component {
using std::bitset;
enum Enum{ foo, bar, baz };
enum{ max = baz, count = max + 1 };
using Set = bitset<count>;
} // namespace component
auto main() -> int
{
auto const mask = component::Set().set( component::foo ).set( component::baz );
}
- 不带大括号的枚举形式
- 枚举环境变量的惯用C++14/C++17方法
- 类似枚举的计算常量
- 如何正确实现和访问运算符的各种自定义枚举器
- 错误:从"int"到枚举c++的转换无效
- C++中构造函数中的枚举
- 访问在 C++ 结构中声明的枚举变量
- 枚举类'classname'的多重定义
- 强枚举类型定义:Clang Bug 还是 C++11 标准不确定性?
- typedef 枚举和枚举类有什么区别?
- 为什么我的开关/机箱在使用枚举时默认?
- 标准::可选枚举的比较运算符
- C++两个源文件之间共享的枚举的静态实例
- 打印没有铸件的枚举可以在C++中吗?
- 枚举成员与静态 int 成员?
- C++:枚举:错误:应使用标识符而不是"}"
- 带有 c++ 的枚举(输入检查)
- 在 qml 中使用 Q_ENUM 和 Q_PROPERTY 作为枚举类
- 为什么 int 类型的枚举类值不能用作 int
- C++枚举是否可以大于 64 位?