Если в вашем 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
, выбрав вместо этого анонимного union
;это позволяет избежать большого количества шаблонов, так как в противном случае я должен был бы написать эти конструкторы внутри union
(потому что это union
конструктор, который удален и должен быть явно определен), а затем добавитьэкспедиторы снаружи;это также значительно упрощает написание деструктора (опять же, это должно было бы быть написано внутри union
, но union
не знает внешнего type
; вы можете обойти это, но это утомительно и многословно); - Мне пришлось явно назвать объединение
Cursor
, в противном случае синтаксически невозможно вызвать его деструктор (исключая уловки шаблонов); - Я не реализовалоператор присваивания;это не сложно, но, честно говоря, это довольно утомительно.Вы можете найти базовый проект (проверьте, если то же самое
type
; если то же самое, выполните обычное задание; в противном случае уничтожьте активного члена и поместите new
на нового) в ссылке, которую я разместил ранее в комментариях.
Все это, как говорится, уже реализовано в C ++ 17 в более общем виде, как std::variant
, так что если у вас естьдостаточно недавний компилятор, вы можете использовать его вместо этого.