如何使用模板创建编译时类字段?

时间:2017-11-14 11:24:07

标签: c++ variadic-templates c++17 template-meta-programming

背景和理由

我正在设计编译时ECS。设计有其特定性 - 例如,将有各种各样的实体。这意味着组件的总数可能相当高,而每个实体的组件数量将相当低(有一些明显的现在 - 几乎无处不在的公共,如SpriteBoundingBox)< / p>

我的方法

我会实现以下界面:

/* Tell the compiler which fields we would use in this entity */
Entity<GraphicsComponent, PhysicsComponent> entity;

/* Populate the handles with the appropriate data (integer, pointer, doesn't matter) */
// via explicit creation
Entity.add<GraphicsComponent>(RenderSystem::create<GraphicsComponent>());
// or in some other way?

我写的Entity课程的开始:

template <typename ...>
class Entity final {};

但是,我不知道如何为各个组件类型创建句柄数据字段,如果它甚至可能的话。任何人都可以帮助我或解释为什么它不起作用(或可能建议不同的解决方案)?

2 个答案:

答案 0 :(得分:2)

只需使用std::tuple即可。注: get要求Components...中的每一个都是不同的类型

template <typename ... Components>
class Entity final { 
    std::tuple<Components...> components;  
    template<typename Component>
    void add(Component component) // possibly cv / ref qualified
    {
        std::get<std::decay_t<Component>>(components) = component;
    }
};

答案 1 :(得分:2)

std::variant用于灵活性和简单性的混合,代价是可能会牺牲一些内存。

template<typename... Components>
class Entity final {
    using variant = std::variant<Components...>;
    std::vector<variant> components;

public:
    template<typename T>
    void add(T&& t) {
        components.push_back(std::forward<T>(t));
    }
};

当组件的大小变化很大时,会出现内存问题。假设一个是1个字节而另一个是200个字节,std::vector中的所有条目将至少大200字节。

另一个解决方案是std::any

template<typename... Components>
class Entity final {
    std::vector<std::any> components;

public:
    template<typename T>
    void add(T&& t) {
        static_assert((std::is_same_v<Components, std::decay_t<T>> || ...));
        components.push_back(std::forward<T>(t));
    }
};

std::any除了非常小的对象之外,肯定会拥有堆上的所有内容,但不会遇到std::variant的上述问题。

在使用std::any的情况下,我们仅使用类型系统来启用检查,而不是管理数据的布局。