Yoh*_*eby 11 c++ enums bit-manipulation bitflags std-bitset
目前我正在使用枚举代表一个小游戏实验中的状态.我声明他们是这样的:
namespace State {
enum Value {
MoveUp = 1 << 0, // 00001 == 1
MoveDown = 1 << 1, // 00010 == 2
MoveLeft = 1 << 2, // 00100 == 4
MoveRight = 1 << 3, // 01000 == 8
Still = 1 << 4, // 10000 == 16
Jump = 1 << 5
};
}
Run Code Online (Sandbox Code Playgroud)
这样我就可以这样使用它们:
State::Value state = State::Value(0);
state = State::Value(state | State::MoveUp);
if (mState & State::MoveUp)
movement.y -= mPlayerSpeed;
Run Code Online (Sandbox Code Playgroud)
但我想知道这是否是实现位标志的正确方法.是否有特殊的容器标志容器?我听说过std::bitset,这是我应该用的吗?你知道更高效的东西吗?
我做得对吗?
inline State::Value operator|(State::Value a, State::Value b)
{ return static_cast<State::Value>(static_cast<int>(a) | static_cast<int>(b)); }
inline State::Value operator&(State::Value a, State::Value b)
{ return static_cast<State::Value>(static_cast<int>(a) & static_cast<int>(b)); }
inline State::Value& operator|=(State::Value& a, State::Value b)
{ return (State::Value&)((int&)a |= (int)b); }
Run Code Online (Sandbox Code Playgroud)
我不得不使用C风格的演员表|=,它没有用static_cast- 任何想法为什么?
STL包含std :: bitset,您可以在这种情况下使用它。
这是足够的代码来说明这个概念:
#include <iostream>
#include <bitset>
class State{
public:
//Observer
std::string ToString() const { return state_.to_string();};
//Getters
bool MoveUp() const{ return state_[0];};
bool MoveDown() const{ return state_[1];};
bool MoveLeft() const{ return state_[2];};
bool MoveRight() const{ return state_[3];};
bool Still() const{ return state_[4];};
bool Jump() const{ return state_[5];};
//Setters
void MoveUp(bool on) {state_[0] = on;}
void MoveDown(bool on) {state_[1] = on;}
void MoveLeft(bool on) {state_[2] = on;}
void MoveRight(bool on) {state_[3] = on;}
void Still(bool on) {state_[4] = on;}
void Jump(bool on) {state_[5] = on;}
private:
std::bitset<6> state_;
};
int main() {
State s;
auto report = [&s](std::string const& msg){
std::cout<<msg<<" "<<s.ToString()<<std::endl;
};
report("initial value");
s.MoveUp(true);
report("move up set");
s.MoveDown(true);
report("move down set");
s.MoveLeft(true);
report("move left set");
s.MoveRight(true);
report("move right set");
s.Still(true);
report("still set");
s.Jump(true);
report("jump set");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
工作正常:http : //ideone.com/XLsj4f
有趣的是,您可以免费获得std :: hash支持,这通常是在各种数据结构中使用状态时所需的条件之一。
编辑:std :: bitset有一个限制,那就是您需要在编译时知道位集中的最大位数的事实。但是,无论如何,枚举都是相同的情况。
但是,如果在编译时不知道位集的大小,则可以使用boost :: dynamic_bitset,根据本文(请参阅第5页),它实际上非常快。最后,根据Herb Sutter的说法,std :: bitset被设计用于通常需要使用std :: vector的情况。
话虽如此,实际上没有任何替代品可以代替真实世界的测试。因此,如果您真的想知道,请进行简介。这将为您提供您所关注的上下文的性能数字。
我还应该提到std :: bitset的优点是enum没有-可以使用的位数没有上限。因此std :: bitset <1000>是完全有效的。
老实说,我认为他们没有一致的模式 。
只需将std::ios_base::openmode和std::regex_constants::syntax_option_type作为在标准库中构建它的两种完全不同的方式即可 - 一种使用结构,另一种使用整个命名空间。两者都是枚举,但结构不同。
检查您的标准库实现,以了解上述两者的实现方式的详细信息。
我认为您的方法是正确的(除了几件事):
1.您可以显式指定基础类型以节省内存;
2.您不能使用未指定的枚举值。
namespace State {
enum Value : char {
None = 0,
MoveUp = 1 << 0, // 00001 == 1
MoveDown = 1 << 1, // 00010 == 2
MoveLeft = 1 << 2, // 00100 == 4
MoveRight = 1 << 3, // 01000 == 8
Still = 1 << 4, // 10000 == 16
Jump = 1 << 5
};
}
Run Code Online (Sandbox Code Playgroud)
和:
State::Value state = State::Value::None;
state = State::Value(state | State::MoveUp);
if (mState & State::MoveUp) {
movement.y -= mPlayerSpeed;
}
Run Code Online (Sandbox Code Playgroud)
关于重载:
inline State::Value& operator|=(State::Value& a, State::Value b) {
return a = static_cast<State::Value> (a | b);
}
Run Code Online (Sandbox Code Playgroud)
由于您使用的是C ++ 11,因此应尽可能使用constexpr一切可能的方法:
inline constexpr State::Value operator|(State::Value a, State::Value b) {
return a = static_cast<State::Value> (a | b);
}
inline constexpr State::Value operator&(State::Value a, State::Value b) {
return a = static_cast<State::Value> (a & b);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7173 次 |
| 最近记录: |