Никогда бы не подумал, что мне эта штука будет полезна, но был очень сильно не прав. Итак, вариативные шаблоны, казалось бы, растут они из вариативных функций и нужно сначала разобраться с ними, но нет, делать этого мы не будем. Давайте сразу к шаблонам, смотрите, шаблоны — это способность унифицировать тип, например, подставлять стандартные типы, но еще лучше, что мы можем подставлять пользовательские типы, конструкторам которых нужны разные наборы параметров для конструирования. Ничего не напоминает? Да, разные наборы параметров в конструкторах это и есть вариативные функции с переменным числом аргументов. Такой инструмент позволяет нам создавать, например, простые функции-фабрики объектов, передавая в них тип в качестве параметра шаблона и параметры для конструктора в качестве переменного числа аргументов. И если допустить, что создаваемые объекты нам нужны в единичном количестве, то искать мы их можем в словаре, где значением является созданный объект, а ключом будет его тип, вернее указатели на них. Это лучше, чем вектор с поиском по индексу. Если понадобится хранение нескольких объектов одного и того же типа, то нужно будет вводить “айдишки” и создавать более сложную фабрику, но это отдельный разговор.
Пример ниже рассматривает создание примитивной компонентной системы, в которой мы создаем компоненты с помощью вариативного шаблона AddComponent.
#include <iostream>
#include <vector>
#include <map>
class Component {
public:
virtual void init() = 0;
};
class Transform : public Component {
public:
Transform(int _x, int _y) : x{_x}, y{_y} {}
void init() override {
std::cout << "transform component ready" << std::endl;
}
private:
int x, y;
};
class Image : public Component {
public:
Image(const std::string& _file) : file{_file} {}
void init() override {
std::cout << "image component ready" << std::endl;
}
private:
std::string file;
};
std::map<const std::type_info *, Component *> componentTypeMap;
template<typename T, typename... TArgs>
T *AddComponent(TArgs &&... args) {
T *newComponent = new T(std::forward<TArgs>(args)...);
componentTypeMap[&typeid(*newComponent)] = newComponent;
return newComponent;
}
template<typename T>
T *GetComponent() {
std::cout << "return [" << typeid(T).name() << "] component";
return static_cast<T *>(componentTypeMap[&typeid(T)]);
}
int main() {
std::vector<Component *> entity;
entity.push_back(AddComponent<Transform>(0, 0));
entity.push_back(AddComponent<Image>("image.png"));
for(auto component : entity){
component->init();
}
GetComponent<Image>();
entity.clear();
return 0;
}
Output:
>>transform component ready
>>image component ready
>>return [5Image] component
No comments:
Post a Comment