一旦你在你的
union
(所以,语言
强制执行
“正确”初始化,即构造函数调用),您必须显式地编写构造函数/析构函数:
#include <SDL/SDL.h>
#include <glm/vec3.hpp>
#include <stdint.h>
#include <new>
#include <vector>
struct Event {
enum Type{
tRaw,
tAction,
tCursor,
} type;
struct Cursor {
glm::vec3 prevPos;
glm::vec3 pos;
};
union {
SDL_Event raw;
struct {
uint16_t actionID;
bool released;
} action;
Cursor cursor;
};
Event(const SDL_Event &raw) : type(tRaw) {
new(&this->raw) SDL_Event(raw);
}
Event(uint16_t actionID, bool released) : type(tAction) {
this->action.actionID = actionID;
this->action.released = released;
}
Event(glm::vec3 prevPos, glm::vec3 pos) : type(tCursor) {
new(&this->cursor) Cursor{prevPos, pos};
}
Event(const Event &rhs) : type(rhs.type) {
switch(type) {
case tRaw: new(&this->raw) SDL_Event(raw); break;
case tAction: memcpy((void *)&action, (const void *)&rhs.action, sizeof(action)); break;
case tCursor: new(&this->cursor) Cursor(rhs.cursor);
}
}
~Event() {
if(type == tCursor) {
this->cursor.~Cursor();
}
// in all other cases, no destructor is needed
}
};
int main() {
// Construction
Event ev(1, false);
SDL_Event foo;
Event ev2(foo);
glm::vec3 pos;
Event ev3(pos, pos);
// Copy construction & destruction
std::vector<Event> events;
events.push_back(ev);
events.push_back(ev2);
events.push_back(ev3);
events.clear();
return 0;
}
一些注意事项:
-
我避开了
data
成员,选择匿名
联盟
;这避免了太多的样板文件,否则我必须在
联盟
(因为它是
联盟
的
已删除且必须明确定义的构造函数,然后在外部添加转发器;它还大大简化了析构函数的写入(同样,它必须在
联盟
但是
联盟
不知道外部
type
你
可以
解决这个问题,但它既冗长又冗长);
-
我必须明确指出
Cursor
联合,否则在语法上不可能调用其析构函数(除非使用模板技巧);
-
我没有实现赋值操作符;它并不复杂,但说实话,它相当繁琐。您可以找到一个基本的蓝图(检查是否相同
类型
;如果相同,执行常规分配;否则,销毁活动成员并放置-
new
在新的上面)
in the link I posted before in the comments
.
所有这些都说,这些东西已经在C++ 17中以更通用的方式实现了。
std::variant
,因此,如果您最近有足够多的编译器,可以考虑改用它。