C++枚举标志用法
C++ enum flag usage
我已经用谷歌搜索了一下,但似乎没有立即可用的明确答案。我试图弄清楚 C++ 中枚举标志的正确用法。我正在开发一个基于 2D 平铺的平台游戏引擎,我想为每个平铺提供标志,以确定哪些边缘可以碰撞。
在一个文件中,我有:
enum CollidableEdges
{
TopEdge = 1,
RightEdge = 2,
BottomEdge = 4,
LeftEdge = 8
};
如何在对象中实际调用这些标志,并在以后的逻辑中使用它们?在我在网上看到的示例中,在操作标志时,除了初始列表之外,它似乎没有在任何地方声明枚举。有人可以澄清到底发生了什么以及如何使用它吗?例如,在创建具有如下定义的新 Tile 对象时:
class Tile: public Entity
{
public:
Tile(std::string obstacleTexture, int, int);
}
我是一个相当新的程序员,所以我确定我正在使用不好的做法或遗漏了一些明显的东西。不要害羞地告诉我。
有人可以澄清到底发生了什么以及如何使用它吗?
初始化特定位
uint8_t flags = uint8_t(TopEdge) | uint8_t(LeftEdge);
设置特定位
flags |= uint8_t(BottomEdge);
清除特定位
flags &= ~(uint8_t(TopEdge) | uint8_t(LeftEdge));
测试特定位
if(flags & uint8_t(BottomEdge) > 0) { // Flag is set (BottomEdge)
}
您需要强制转换它的原因是,如果您有类似 TopEdge | LeftEdge
的表达式,编译器将不接受原始enum
类型作为结果。
为了摆脱强制转换,您还可以定义重载operator|()
、operator&()
等:
CollidableEdges operator|(CollidableEdges left, CollidableEdges right) {
return static_cast<CollidableEdges>(static_cast<unsigned>(left) |
static_cast<unsigned>(right));
}
// etc.
允许简单地编写
CollidableEdges edges = TopEdge | LeftEdge;
注意:
尽管上述语句可以正常工作,但恕我直言,它们对预期语义的可读性很差。我个人更喜欢以下解决方案:
enum class CollidableEdgeBitPos : size_t {
TopEdge ,
RightEdge ,
BottomEdge ,
LeftEdge
};
typedef std::bitset<4> CollidableEdges;
CollidableEdges edges;
edges[CollidableEdgeBitPos::RightEdge] = true;
edges[CollidableEdgeBitPos::BottomEdge] = false;
CollidableEdges
是一种类型,你可以在任何可以使用类型的地方使用它(例如,它可以是方法中参数之一的类型。
标签是在枚举的包含范围内有效的标识符。例如,如果在class XX
中定义枚举,则可以使用 XX::TopEdge
访问标签
,但最好检查(例如开关/大小写)而不是从 int 盲转换。
强制转换为 int 将生成与标签关联的值。这是静态常量整数常量的替代方法。例如,在您的示例中,每个标签都关联一个逐位不相交值,您可以使用按位或(例如 TopEdge|LefEdge)[但只是因为它们是不相交的整数值)。
给定数值,看起来你的枚举正在用于定义位掩码。 在这种情况下,通常的程序将是为他们使相关运营商超载,以便您可以适当地使用它们:
inline CollidableEdges
operator|( CollidableEdges lhs, CollidableEdges rhs )
{
return static_cast<CollidableEdges>(
static_cast<unsigned>( lhs) | static_cast<unsigned>( rhs ) );
}
等。 (你需要|
、|=
、&
、&=
和~
。 这些运算符通常应与枚举位于同一标头中定义。 然后,使用它们的对象也将采用作为参数的CollidableEdge
:
Tile::Tile( std::string const& texture, CollidableEdge edges )...
等。
传统上,枚举常量的名称是在与枚举本身相同的范围内定义;在 C++11 中,您还有可能将它们限制为枚举,通过声明enum class CollidableEdge
,而不是 enum CollidableEdge
;在这种情况下,您必须指定 CollidableEdge::TopEdge | CollidableEdge::LeftEdge
,而是不仅仅是TopEdge | LeftEdge
. (另一方面,这意味着它们不会与您可能想要的任何其他符号发生冲突定义。
最后,鉴于|
和&
的"错误"先例,我经常发现将运算符+
、-
和*
定义为好吧,a + b
相当于a | b
(您正在向集合),a - b
相当于a & ~ b
(您正在减去集合中的值)和a * b
与a & b
相同。
- 这个指针在c++中的用法
- 即使使用调试编译标志,表达式也是"optimized out"
- 当C++中需要自动删除时,这是静态的正确用法吗?
- 在 CMake 中为每个目标设置编译器/链接器标志
- libstdc++ 文件系统中未初始化的用法?
- 复制和交换习惯用法与移动操作之间的交互
- 类作用域的类型别名"using":[何时]方法中的用法可以先于类型别名?
- 命名参数习惯用法和(抽象)基类
- File.cpp.o:OpenPose 标志 CMakeFiles/.. 的多重定义/main.cpp.o:首先在这里定
- 在轮班操作后使用携带标志
- 省略号在C++中的所有用法
- 如何找出引入AVX标志的内容
- () 在 C++ 11 中的特殊而奇怪的用法?
- 构造函数的用法
- I2C 文件描述符上的 I2C 总线可写/可读标志
- C ++是否有C ++ 17 OSX 10.13.6的标志
- 模板类中自动的类用法不完整
- 每次使用带有LOCK_EX标志的LOCK_NB时,相同的程序/进程都会获取锁
- CMake 3.5 中的链接器标志位置
- C++枚举标志用法