【问题标题】:Keep track of instantiated templated types C++跟踪实例化的模板类型 C++
【发布时间】:2016-11-08 21:03:46
【问题描述】:

我正在修改实体组件系统的实体管理器。由于组件没有重叠的功能,我不希望它们有一个我可以存储的共享库。

所以我想出了这样的东西:

#include <vector>
#include <memory>
#include <iostream>

class Component1{};
class Component2{};
class Component3{};

class Manager{
public:
  template<typename T> static std::vector<std::shared_ptr<T>> component;

  template<typename T> static std::shared_ptr<T> getComponent(int nth){
    return component<T>[nth];
  }

  template<typename T> static std::shared_ptr<T> addComponent(int nth){
    return component<T>[nth] = shared_ptr<T>(new T());
  }

  static void addEntity(){
    // push back a nullptr for every instantiated component<>
  }

  static void removeEntity(int nth){
    // set the nth index of every component<> to nullptr
  }
};

template<typename T>
std::vector<std::shared_ptr<T>> Manager::component = std::vector<std::shared_ptr<T>>();

int main(){
  Manager::component<Component1>;
  Manager::component<Component2>;
  Manager::component<Component3>;

  Manager::addEntity();
  auto cmp2 = Manager::getComponent<Component2>(0);

  Manager::removeEntity(0);

  std::cin.get();
  return 0;
}

如何迭代两个函数的实例化组件?尝试使用 type_info 的向量来存储组件类型,但我永远无法从中获取正确的类型以用作模板参数。

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    您可以从对get a unique ID for your types 使用模板元编程技巧开始。 然后,您可以使用带有 唯一类型 ID 的地图,而不是使用可变模板向量。通过使用基类 Component 引入多态性,再加上 static_cast(以降低运行时成本),您可以轻松地重新实现以前的 addComponentgetComponent 方法。由于地图访问,它们的成本会稍微高一些,但最终您可以通过遍历地图来实现 addEntityremoveEntity,完全按照您的意愿行事想要。

    这是我对上述想法的实现:

    #include <vector>
    #include <map>
    #include <memory>
    #include <iostream>
    
    typedef void(*unique_id_type)();
    
    template <typename... Arguments>
    struct IdGen {
        static constexpr inline unique_id_type get_unique_id()
        {
            return &IdGen::dummy;
        }
    
    private:
        static void dummy() {};
    
    };
    
    class Component {};
    class Component1 : public Component {};
    class Component2 : public Component {};
    class Component3 : public Component {};
    
    class Manager {
    public:
        static std::map<unique_id_type, std::vector<std::shared_ptr<Component>>> components;
    
        template<typename T> static std::shared_ptr<T> getComponent(int nth) {
            return std::static_pointer_cast<T>(components[IdGen<T>::get_unique_id()][nth]);
        }
    
        template<typename T> static std::shared_ptr<T> addComponent(int nth) {
            return std::static_pointer_cast<T>(components[IdGen<T>::get_unique_id()][nth] = std::shared_ptr<T>(new T()));
        }
    
        static void addEntity() {
            for (auto& component : components)
                component.second.push_back(nullptr);
        }
    
        static void removeEntity(int nth) {
            for (auto& component : components)
                component.second[nth] = nullptr;
        }
    };
    
    std::map<unique_id_type, std::vector<std::shared_ptr<Component>>> Manager::components = {
        { IdGen<Component1>::get_unique_id(), {} },
        { IdGen<Component2>::get_unique_id(), {} },
        { IdGen<Component3>::get_unique_id(), {} },
    };
    
    int main() {
        Manager::addEntity();
      auto cmp2 = Manager::getComponent<Component2>(0);
    
      Manager::removeEntity(0);
    
      std::cin.get();
      return 0;
    }
    

    PS = 此代码使用 C++11 功能,例如 constexpr 和列表初始化,但由于您已经在使用 C++14(即使您没有将问题标记为 C++14),我认为这是没问题。

    PS 2 = 由于我使用 static_cast 向下转换,因此您不应该对组件使用虚拟继承(阅读 why)。

    【讨论】:

      猜你喜欢
      • 2021-12-24
      • 1970-01-01
      • 1970-01-01
      • 2019-10-28
      • 1970-01-01
      • 2016-03-16
      • 2014-12-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多