代码之家  ›  专栏  ›  技术社区  ›  Anne Quinn

为什么不能创建包含vec3对象的联合?

  •  5
  • Anne Quinn  · 技术社区  · 7 年前

    我似乎无法创建一个成员是或包含 glm::vec3 对象(表示坐标的对象,在本例中包含3个浮动)。 (source code for glm::vec)

    它用于以下代码:

    struct Event {
        enum Type{
            tRaw,
            tAction,
            tCursor,
        } type;
        union {
            SDL_Event raw;
            struct {
                uint16 actionID;
                bool released;
            } action;
            struct {
                glm::vec3 prevPos;
                glm::vec3 pos;
            } cursor; // offending object, compiles if this is removed
        } data;
    };
    

    Visual Studio提供以下IntelliSense错误。

    "Error: the default constructor of "union Event::<unnamed>" cannot be referenced -- it is a deleted function"

    如果将其删除,则联盟编译时不会出现任何问题。可能是什么导致了这个问题,我能做些什么来补救它吗?

    1 回复  |  直到 7 年前
        1
  •  7
  •   Matteo Italia    7 年前

    一旦你在你的 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 ,因此,如果您最近有足够多的编译器,可以考虑改用它。