C++ 为什么这个联盟显然持有不止一种价值观?

C++ 为什么这个联盟显然持有不止一种价值观?,c++,sdl,unions,C++,Sdl,Unions,我不熟悉使用联合体,对这个测试是如何通过的感到困惑,SDL\u Event作为一个联合体: TEST(basic_check, test_eq) { Dot dot; SDL_Event event; // this is a union, see below event.type = SDL_KEYDOWN; // <= I use one member here SDL_Keysym keysym; // this is

我不熟悉使用联合体,对这个测试是如何通过的感到困惑,
SDL\u Event
作为一个联合体:

TEST(basic_check, test_eq) {
  Dot dot;

  SDL_Event event;            // this is a union, see below
  event.type = SDL_KEYDOWN;   // <= I use one member here

  SDL_Keysym keysym;          // this is a struct
  keysym.sym = SDLK_UP;
  event.key.keysym = keysym;  // <= I use another member here

  dot.handleEvent(event);     // <= but this function accesses value of the first member

  EXPECT_EQ(-Dot::DOT_VEL, dot.getVelY());
}
我很困惑,因为
if
条件访问了工会的两个成员(参见上面的注释)。我以为他们是排他的

有关信息,
SDL\u事件
SDL\u键盘事件
的定义如下:

typedef union SDL_Event
{
    Uint32 type;                    /**< Event type, shared with all events */
    SDL_CommonEvent common;         /**< Common event data */
    SDL_WindowEvent window;         /**< Window event data */
    SDL_KeyboardEvent key;          /**< Keyboard event data */
    ...            // and a long list of other events 
    ...
} SDL_Event;


typedef struct SDL_KeyboardEvent
{
    Uint32 type;        /**< ::SDL_KEYDOWN or ::SDL_KEYUP */
    Uint32 timestamp;
    Uint32 windowID;    /**< The window with keyboard focus, if any */
    Uint8 state;        /**< ::SDL_PRESSED or ::SDL_RELEASED */
    Uint8 repeat;       /**< Non-zero if this is a key repeat */
    Uint8 padding2;
    Uint8 padding3;
    SDL_Keysym keysym;  /**< The key that was pressed or released */
} SDL_KeyboardEvent;
typedef联合SDL_事件
{
Uint32类型;/**<事件类型,与所有事件共享*/
SDL_CommonEvent common;/**<公共事件数据*/
SDL_WindowEvent window;/**
关于工会在任何给定时间最多有一名成员处于活动状态的说法是正确的

但该标准做出了一项保证,以促进工会的使用(尤其是找出哪一个是积极因素,如此处所示):

9.5/1:(…)如果标准布局联合包含多个标准布局结构 共享一个共同的初始序列,如果 标准布局联合类型包含一个标准布局 结构,允许检查任何 标准布局结构成员的定义

在您的示例中,
SDL\u事件
union有一个union成员
Uint32类型
,所有的
SDL\u XXXEvent
结构也以
Uint32
开头。这是常见的初始序列,因此可以使用任何成员对其进行检查(最简单的是
类型

编辑:有趣的评论(摘自评论)

正如您所指出的,测试不仅仅是检查:它还使用
事件.type
写入
类型
,然后在
事件.key
中分配
键ym
。因此,您想知道活动成员的更改(从
类型
更改为
)是否不会使公共初始序列无效

请确保这是完美的。检查时的C++保证确保在“代码>事件的分配之后。类型< /代码>(通用初始序列),<代码>事件。键。类型< /代码>也是<代码> SDLYKEYDOWS/<代码>。当您只更改
event.key.keysim
时,没有理由更改
类型
的值


但是请注意,
timestamp
WindowsID
event.key
的其他成员处于未定义状态。你的测试没有使用它们,所以没有理由失败。但为了避免此类潜在问题,更好的方法可能是构造一个
SDL_键盘事件
,正确初始化它并将整个结构复制到
event.key

关于工会在任何给定时间最多有一个成员处于活动状态的说法是正确的

但该标准做出了一项保证,以促进工会的使用(尤其是找出哪一个是积极因素,如此处所示):

9.5/1:(…)如果标准布局联合包含多个标准布局结构 共享一个共同的初始序列,如果 标准布局联合类型包含一个标准布局 结构,允许检查任何 标准布局结构成员的定义

在您的示例中,
SDL\u事件
union有一个union成员
Uint32类型
,所有的
SDL\u XXXEvent
结构也以
Uint32
开头。这是常见的初始序列,因此可以使用任何成员对其进行检查(最简单的是
类型

编辑:有趣的评论(摘自评论)

正如您所指出的,测试不仅仅是检查:它还使用
事件.type
写入
类型
,然后在
事件.key
中分配
键ym
。因此,您想知道活动成员的更改(从
类型
更改为
)是否不会使公共初始序列无效

请确保这是完美的。检查时的C++保证确保在“代码>事件的分配之后。类型< /代码>(通用初始序列),<代码>事件。键。类型< /代码>也是<代码> SDLYKEYDOWS/<代码>。当您只更改
event.key.keysim
时,没有理由更改
类型
的值

但是请注意,
timestamp
WindowsID
event.key
的其他成员处于未定义状态。你的测试没有使用它们,所以没有理由失败。但为了避免此类潜在问题,更好的方法可能是构造一个
SDL_KeyboardEvent
,对其进行适当初始化,并将整个结构复制到
event.key

如果仔细观察,您会发现它主要是一个unio结构,其中每个结构都有相同的初始签名(具有单个8位无符号整数作为第一个成员)

这就是它工作的原因。即使联合体中的结构具有不同的大小,所有结构都将具有与第一个成员相同的成员
类型

这是一种模拟继承的简单方法,这意味着
SDL_事件中的所有结构都是继承的同级
typedef union SDL_Event
{
    Uint32 type;                    /**< Event type, shared with all events */
    SDL_CommonEvent common;         /**< Common event data */
    SDL_WindowEvent window;         /**< Window event data */
    SDL_KeyboardEvent key;          /**< Keyboard event data */
    ...            // and a long list of other events 
    ...
} SDL_Event;


typedef struct SDL_KeyboardEvent
{
    Uint32 type;        /**< ::SDL_KEYDOWN or ::SDL_KEYUP */
    Uint32 timestamp;
    Uint32 windowID;    /**< The window with keyboard focus, if any */
    Uint8 state;        /**< ::SDL_PRESSED or ::SDL_RELEASED */
    Uint8 repeat;       /**< Non-zero if this is a key repeat */
    Uint8 padding2;
    Uint8 padding3;
    SDL_Keysym keysym;  /**< The key that was pressed or released */
} SDL_KeyboardEvent;