跟踪实例化的模板化类型C ++

时间:2016-11-08 21:03:46

标签: c++ templates

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

所以我想出了类似的东西:

#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的向量来存储Component类型,但我永远无法从中获取正确的类型以用作模板参数。

1 个答案:

答案 0 :(得分:2)

您可以首先使用模板元编程技巧get a unique ID for your types。 然后,您可以使用带有唯一类型ID 的地图,而不是您的变量模板向量。通过将多态性与基础Component类相结合,再加上static_cast(以减少运行时成本),您可以轻松地重新实现以前的 addComponent getComponent 方法。由于地图访问权限,它们的成本会稍微高一些,但最终您可以通过迭代地图来实现 addEntity removeEntity ,完全按照您的要求执行想要的。

以下是我对上述想法的实施:

#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)。