使用指针算法遍历均匀POD结构

时间:2018-03-26 01:02:27

标签: c++

假设我正在编写游戏,设计一种输入重新映射的机制。它有这两种结构:

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;
}

因为我希望这段代码尽可能通用,所以我想把两个结构当作一个&#34;数组&#34; 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。

那么,我设计的这种机制是否符合标准的观点?

1 个答案:

答案 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库。