假设我正在编写游戏,设计一种输入重新映射的机制。它有这两种结构:
struct KeyboardSettings
{
InputSource dashInput;
InputSource jumpInput;
InputSource bombInput;
InputSource switchScreenLeft;
InputSource switchScreenRight;
InputSource pauseInput;
InputSource moveUp;
InputSource moveDown;
InputSource moveLeft;
InputSource moveRight;
};
struct JoystickSettings
{
InputSource dashInput;
InputSource jumpInput;
InputSource bombInput;
InputSource switchScreenLeft;
InputSource switchScreenRight;
InputSource pauseInput;
InputSource movementAxisX;
InputSource movementAxisY;
};
现在,我希望我的系统在重新分配密钥时能够找到重复项,类似于:
void UIInputRemappingButtonGroup::assignRemappingUniquely(InputSource& curSource, InputSource newSource)
{
for (InputSource* orgSource : /* iterate through structure's members */)
if (*orgSource == newSource) *orgSource = curSource;
curSource = newSource;
}
因为我希望这段代码尽可能通用,所以我想把两个结构当作一个"数组" InputSource
的{{1}},UIInputRemappingButtonGroup
会收到代表数组开头和大小的InputSource*
和size_t
,我会这样做:< / p>
void UIInputRemappingButtonGroup::assignRemappingUniquely(InputSource& curSource, InputSource newSource)
{
for (InputSource* orgSource = sourceCollection; orgSource != sourceCollection+sourceCollectionSize; ++orgSource)
if (*orgSource == newSource) *orgSource = curSource;
curSource = newSource;
}
因此,如果我在屏幕上重新设置键盘按钮,我会有一个KeyboardSettings keyboardSettings
,我会将它传递给UIInputRemappingButtonGroup
,如下所示:
buttonGroup.setInputSourceCollection(&keyboardSettings.dashInput, sizeof(keyboardSettings)/sizeof(InputSource));
同样,如果我有一个JoystickSettings joystickSettings
,我可以使用以下代码将其传递给UIInputRemappingButtonGroup
:
buttonGroup.setInputSourceCollection(&joystickSettings.dashInput, sizeof(joystickSettings)/sizeof(InputSource));
问题是,我怀疑这会触发未定义的行为。尽管这两个结构是标准布局和平凡的(因而是POD),但我没有在标准上找到支持这种技术有效性的任何内容,或者至少将其从UB领域中取出。这样安全吗?
InputSource
定义如下:
class InputSource final
{
private:
enum class Type : uint8_t { Keyboard, MouseButton, MouseAxis, JoystickButton, JoystickAxis };
Type type;
size_t attribute;
// Constructor private
InputSource() = default;
InputSource(Type type, uint32_t attr) : type(type), attribute(attr) {}
public:
std::string getInputName(LocalizationManager& lm);
static InputSource keyboardKey(size_t scanCode);
static InputSource mouseButton(sf::Mouse::Button button);
static InputSource mouseX, mouseY;
static InputSource mouseWheel(sf::Mouse::Wheel wheel);
static InputSource joystickButton(unsigned int button);
static InputSource joystickAxis(sf::Joystick::Axis axis);
friend bool operator==(InputSource in1, InputSource in2);
friend bool operator<(InputSource in1, InputSource in2);
friend bool readFromStream(sf::InputStream& stream, InputSource& in);
friend bool writeToStream(OutputStream& stream, const InputSource& in);
friend struct std::hash<InputSource>;
};
如图所示,它满足标准布局要求(所有非静态数据成员具有相同的访问控制,没有虚函数或虚基类,没有引用类型的非静态数据成员,以及所有非静态数据成员标准布局),以及琐碎的要求(普通构造函数,复制操作符和析构函数),所以它也是POD。
那么,我设计的这种机制是否符合标准的观点?
答案 0 :(得分:2)
如果您希望将结构视为数组,那么使用实际数组通常是有意义的。这个数组可以安全迭代。
struct KeyboardSettings
{
enum input {
dashInput,
jumpInput,
bombInput,
switchScreenLeft,
switchScreenRight,
pauseInput,
moveUp,
moveDown,
moveLeft,
moveRight,
count,
};
InputSource sources[count]; // you can use std::array if you prefer
};
用法:
using i = KeyboardSettings::input;
KeyboardSettings s;
s.sources[i::moveUp];
// instead of
// s.moveUp;
通过重载下标运算符,可以将其简化为s[i::moveUp]
。
如果你真的想继续使用会员,那就是Boost Fusion库。