从向量的 std::元组中迭代选定的向量

Iterate over selected vectors from a std::tuple of vectors

本文关键字:向量 迭代 元组 std      更新时间:2023-10-16

我正在尝试在 C++11/14 中静态实现实体-组件-系统模式。我已经设法为我的实体制作了一个容器,并且我正在尝试添加功能来处理内部数据。这是我到目前为止的代码:

template<typename... Components>
struct Entity {
  std::tuple<Components...> comps;
  Entity() = default;
  Entity(Components... cs) {
    comps = std::make_tuple(cs...);
  };
};
template<typename... EntityTypes>
struct EntityCollection {
  std::tuple<std::vector<EntityTypes>...> entities;
  template<typename EntityType>
  void add(EntityType e) {
    auto& cont = std::get<std::vector<EntityType>>(entities);
    cont.push_back(e);
  };
  template<typename... Components, typename F>
  void for_each_containing(F f) {
     // todo... apply f on all entities for which 'Components' 
     // are a subset of those in the entity.
  };
};

我见过使用boost fusion(和stl adaptor)和通用lambda循环元组中的所有元素的代码,如下所示:

// inside entity class
void update() {
  for_each(comps, [](auto& c) { c.update(); }; // assuming all components has an update function
};

但是,我想应用一个包含特定组件集的所有实体的函数,如for_each_containing函数所建议的那样。我一直在尝试使用融合中的filter_view编写一些东西,但没有成功......

任何帮助非常感谢!

实用工具:

#include <iostream>
#include <tuple>
#include <vector>
#include <type_traits>
template <typename... Ts>
struct pack {};
template <typename T, typename... Ts>
constexpr bool Contains = false;
template <typename T, typename U, typename... Ts>
constexpr bool Contains<T, U, Ts...> = Contains<T, Ts...>;
template <typename T, typename... Ts>
constexpr bool Contains<T, T, Ts...> = true;
template <bool...> 
constexpr bool All = true;
template <bool Head, bool... Tail>
constexpr bool All<Head, Tail...> = Head && All<Tail...>;
template <typename Subset, typename Set>
struct IsSubset;
template <typename... Ts, typename... Us>
struct IsSubset<pack<Ts...>, pack<Us...>>
    : std::integral_constant<bool, All<Contains<Ts, Us...>...>> {};

Entity 使用示例 update 成员函数:

template <typename... Components>
struct Entity
{
    std::tuple<Components...> comps;
    Entity() = default;
    Entity(Components... cs)
        : comps(cs...)
    {
    }
    void update()
    {
        std::cout << "Updating " << __PRETTY_FUNCTION__ << std::endl;
    }
};

EntityCollection apply 功能:

template <typename... EntityTypes>
struct EntityCollection
{
    std::tuple<std::vector<EntityTypes>...> entities;
    template <typename EntityType>
    void add(EntityType e)
    {
        auto& cont = std::get<std::vector<EntityType>>(entities);
        cont.push_back(e);
    }
    template <typename... Components, typename F>
    void for_each_containing(F f)
    {        
        using expander = int[];
        (void)expander{ 0, (void(
             apply<Components...>(std::get<std::vector<EntityTypes>>(entities), f)
        ), 0)... };
    }
    template <typename... Components, typename... Ts, typename F>
    auto apply(std::vector<Entity<Ts...>>& entities, F f)
        -> std::enable_if_t<IsSubset<pack<Components...>, pack<Ts...>>{}>
    {
        for (auto& v : entities)
        {
            f(v);
        }
    }   
    template <typename... Components, typename... Ts, typename F>
    auto apply(std::vector<Entity<Ts...>>&, F)
        -> std::enable_if_t<!IsSubset<pack<Components...>, pack<Ts...>>{}>
    {
    } 
};

测试:

int main()
{
    Entity<int, short> a;
    Entity<long, int> b;
    Entity<float, double> c;
    EntityCollection<Entity<int, short>,
                     Entity<long, int>,
                     Entity<float, double>> collection;
    collection.add(a);
    collection.add(b);
    collection.add(c);
    collection.for_each_containing<int>([](auto& c){ c.update(); });
    collection.for_each_containing<float>([](auto& c){ c.update(); });
    collection.for_each_containing<short>([](auto& c){ c.update(); });
    collection.for_each_containing<short, int>([](auto& c){ c.update(); });
}

输出:

Updating void Entity<int, short>::update() [Components = <int, short>]
Updating void Entity<long, int>::update() [Components = <long, int>]
Updating void Entity<float, double>::update() [Components = <float, double>]
Updating void Entity<int, short>::update() [Components = <int, short>]
Updating void Entity<int, short>::update() [Components = <int, short>]

演示