我有一个像这样声明的方向的枚举:
enum class ShootingDirection
{
Down,
Up,
Right,
Left
};
我还声明了该类型的类成员,其值需要在某个方法中交换或反转。所谓交换或反转,我指的是向下->向上(反之亦然)和向右->向左(同样反之亦然)。
我使用的不是switch
或一堆if…else if,而是像这样声明的std::map
:
std::map<ShootingDirection, ShootingDirection> _invertedDirectionsMap;
它充满了这样的数据:
_invertedDirectionsMap[ShootingDirection::Down] = ShootingDirection::Up;
_invertedDirectionsMap[ShootingDirection::Up] = ShootingDirection::Down;
_invertedDirectionsMap[ShootingDirection::Right] = ShootingDirection::Left;
_invertedDirectionsMap[ShootingDirection::Left] = ShootingDirection::Right;
类型为ShootingDirection的变量的反转则相当简单(假设它已初始化):
_direction = _invertedDirectionsMap[_direction];
我认为这是对地图的愚蠢使用和不必要的开销。有更聪明的方法吗?
顺便问一下,这个问题属于代码审查还是这里?我真的不熟悉标准。
我通常在一个圆中布置方向枚举(基本上与从x轴测量角度的方式相匹配。因此:
enum ShootingDirection { Right, Down, Left, Up };
匹配0度、90度、180度、270度。这(对我来说)使这成为一个直观的布局。
则反向方向简单地为:(dir + 2) % 4
。或者更全面地说:
int InvertDirection(int dir)
{
return (dir + 2) % 4;
}
我喜欢这个,因为我觉得它使用起来相当直观。顺时针方向转动为(dir + 1) % 4
,逆时针方向转动(dir + 3) % 4
。
它也可以很容易地扩展到更多的方向。我把它用于六边形方向:反转方向现在是(dir + 3) % 6
。
其他人已经开始暗示这个解决方案,但这很快,避免了你说不想要的切换语句:
enum ShootingDirection {
Down = -2,
Up = 2,
Right = 1,
Left = -1
};
inline ShootingDirection invert(ShootingDirection d) {
return static_cast<ShootingDirection>(-static_cast<int>(d));
}
理想情况下,这应该只对一条汇编指令进行内联编译。
是:改为使用switch
语句。它将大大提高效率。如果这还不够好,可以考虑一下:
enum class ShootingDirection
{
Down = 1,
Up = -1,
Right = 2,
Left = -2
};
然后可以通过算术求反(当然还有从int到int的强制转换)进行反转。
enum class Direction {
UP = 1,
DOWN = 2,
LEFT = 3,
RIGHT = 4
};
enum class InvertedDirection {
UP = 2,
DOWN = 1,
LEFT = 4,
RIGHT = 3
};
InvertedDirection getInvertedDirection(Direction dir) {
return static_cast<InvertedDirection>(dir);
}
这是你跑得最快的。使用静态强制转换,然后交换反转值,你真的不会比这更快。
函数实际上只是一个助手,你可以在任何你喜欢的地方进行静态转换。无论哪种方式,这都将阻止编译器发出任何转换代码。
有一种方法可以做到这一点,而无需分支。
http://coliru.stacked-crooked.com/a/4b0a1e3c58b74004
诀窍是:
/* The direction type is 8 bits, only the first 2 are used */
/* The first 2 bits have the following meanings */
typedef unsigned char direction;
const direction down = 'x00'; /* 00000000 */
const direction up = 'x03'; /* 00000011 */
const direction left = 'x01'; /* 00000001 */
const direction right = 'x02'; /* 00000010 */
/* All other values are interpreted by first zeroing out the last 6 bits */
/* Use to zero out all bits but the last two, also for XORing */
static const direction oneone = 'x03';
inline direction xorflip(const direction d)
{
/*
* XOR with 11
* 00 ^ 11 = 11, down to up
* 01 ^ 11 = 10, left to right
* 10 ^ 11 = 01, right to left
* 11 ^ 11 = 00, up to down
*/
return d ^ oneone;
}
您问:
有更聪明的方法吗?
这是另一种扭转方向的方法:
#include <iostream>
enum class ShootingDirection : unsigned char
{
Up = 0x00,
Down = 0xFF,
Left = 0x01,
Right = 0xFE
};
ShootingDirection reverseDirection(ShootingDirection dir)
{
return ShootingDirection((unsigned char)dir ^ 0xFF);
}
int main()
{
ShootingDirection up = ShootingDirection::Up;
ShootingDirection down = ShootingDirection::Down;
ShootingDirection left = ShootingDirection::Left;
ShootingDirection right = ShootingDirection::Right;
std::cout << "Up: " << (int)up << ", Reverse: " << (int)reverseDirection(up) << std::endl;
std::cout << "Down: " << (int)down << ", Reverse: " << (int)reverseDirection(down) << std::endl;
std::cout << "Left: " << (int)left << ", Reverse: " << (int)reverseDirection(left) << std::endl;
std::cout << "Right: " << (int)right << ", Reverse: " << (int)reverseDirection(right) << std::endl;
return 0;
}
输出:
Up: 0, Reverse: 255
Down: 255, Reverse: 0
Left: 1, Reverse: 254
Right: 254, Reverse: 1