我需要使用各种值的枚举,在这种情况下是各种建筑物。其中大多数都是独一无二的,但有一些我希望是等同的。我的意思如下:
enum class EPiece: uint8 {
Ceiling,
Table,
Door,
WestWall,
NorthWall,
SouthWall,
EastWall,
Wall,
Floor
};
我希望Wall == WestWall
成为true
,以及Wall == NorthWall
等。但是,WestWall == NorthWall
是假的。
为什么我这样做是因为我正在制作一个游戏,其中各个部分的定义基于它们是什么/它们在哪里。玩家必须按预定顺序放置各种棋子。玩家首先必须放置NorthWall
件。他们将有各种各样的作品,并且必须选择Wall
件,并且必须尝试将其放在NorthWall
件上。游戏会检查两者是否相同(在这种情况下为true
),以及当前要放置的作品是NorthWall
。如果他们试图将它放在WestWall
件上,它就会失败,因为它还不是那个阶段。
我想通过标志做这件事,做像
这样的事情WestWall = 0x01,
NorthWall = 0x02,
SouthWall = 0x04,
EastWall = 0x08,
Wall = WestWall | NorthWall | SouthWall | EastWall
并通过执行以下操作进行检查:
// SelectedPiece is the Piece the Player selected and is attempting to place
// PlacedOnPiece is the Piece that we are attempting to place on top of
// CurrentPieceToPlace is what Piece we are supposed to place at this stage
if ((CurrentPieceToPlace == PlacedOnPiece) && (SelectedPiece & PlacedOnPiece != 0)) {
}
问题是,我有很多碎片,我的理解是让旗帜工作我必须使用两个的力量。这意味着如果我使用uint32
我最多可以拥有32件,而且我不想受此限制。我可能只需要20左右,但我不想被卡住。
有什么建议吗?此时我需要使用枚举,所以我不能尝试不同的类型。
答案 0 :(得分:2)
我建议不要重载==
以具有这种意义。 ==
通常是可传递的(如果A == B和B == C,那么A == C),如果它不能传递,否则“理智”代码将会中断。
从你的枚举开始:
enum class EPiece: uint8 {
Ceiling,
Table,
Door,
WestWall,
NorthWall,
SouthWall,
EastWall,
Wall,
Floor
};
现在定义一个can_be_used_as_a
关系。
bool can_be_used_as_a( EPiece x, EPiece used_as_a_y ) {
if (x==y) return true;
switch(x) {
case Wall: {
switch(used_as_a_y) {
case WestWall:
case EastWall:
case NorthWall:
case EastWall:
return true;
default: break;
}
}
default: break;
}
switch(used_as_a_y) {
case Wall: {
switch(x) {
case WestWall:
case EastWall:
case NorthWall:
case EastWall:
return true;
default: break;
}
}
default: break;
}
return false;
}
现在can_be_used_as_a( WestWall, Wall )
为true
,因为WestWall
可以用作Wall
。同样,Wall
可以用作WestWall
。但WestWall
不能用作EastWall
。
如果你想要稍微清晰的语法,我们可以写一个命名运算符:
namespace named_operator {
template<class D>struct make_operator{make_operator(){}};
template<class T, char, class O> struct half_apply { T&& lhs; };
template<class Lhs, class Op>
half_apply<Lhs, '*', Op> operator*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, '*', Op>&& lhs, Rhs&& rhs )
-> decltype( invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) ) )
{
return invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
}
对于12行命名的运算符库,使用如下:
struct used_as_a_tag{};
static const named_operator::make_operator<used_as_a_tag> can_use_as_a;
bool invoke( EPiece x, used_as_a_tag, EPiece y ) {
return can_be_used_as_a(x,y);
}
现在我们可以这样做:
if (x *can_use_as_a* y) {
}
操作符出现在左右操作数之间。但这可能会走得太远。
最后,请考虑使用enum class
代替enum
。
答案 1 :(得分:1)
你正朝着正确的方向前进。你拥有的每种墙类型代表一个位,这太棒了。现在你所要做的就是将它们组合在Wall
中,并在你的支票中提取它们,所以:
WestWall = 0x01, //0b0001
NorthWall = 0x02, //0b0010
SouthWall = 0x04, //0b0100
EastWall = 0x08, //0b1000
Wall = 0xF //0b1111
现在,要检查枚举的一个值是否代表另一个值,你应该写下这样的东西:
bool isSame(EPiece first, EPiece second)
{
//if they are the same, they are, well... the same.
if(first == second)
return true;
//this only leaves the bits that are present in both values, so
//if the result is different from 0, then second is a part of first, so
//we return true
else if(first & second)
return true;
//if we are here, then first and second are unrelated
return false;
}
答案 2 :(得分:1)
您可以定义自己的比较运算符,如下所示:
bool operator==(EPiece lhs, EPiece rhs)
{
if (int(lhs) == int(EPiece::Wall) &&
(int(rhs) == int(EPiece::NorthWall) ||
int(rhs) == int(EPiece::SouthWall))) // lots more cases...
{
return true;
}
return int(lhs) == int(rhs);
}
请注意,上述的声明(虽然不一定是定义)必须在您希望比较这些内容的任何地方都可见,因此您应该在枚举声明旁边声明它。
答案 3 :(得分:0)
以下是两种略有不同的可能性:
enum {
Flag0 = 1 << 0,
Flag1 = 1 << 1,
Flag2 = 1 << 2,
Flag3 = 1 << 3,
FlagMask = 0x07
}
if (value & FlagMask) // it's got some flags
{ ... }
if (value & Flag3) // Flag3
{ ... }
和
enum {
ItemA0,
ItemABegin = ItemA0,
ItemA1,
ItemA2,
// insert ItemAs here
ItemAEnd,
ItemB0,
ItemBBegin = ItemB0,
ItemB1,
// insert ItemBs here
ItemBEnd,
}
if (ItemABegin <= value && value < ItemAEnd) // it's some ItemA
{ ... }
if (ItemBBegin <= value && value < ItemBEnd) // it's some ItemB
{ ... }
switch (value) { // switch on specific types
case ItemB0: ... break;
case ItemB1: ... break;
}
第二个版本仍然封装了枚举类型的概念。