Я изучаю ECS и сейчас пытаюсь внедрить компоненты для своего проекта.
Итак, чтобы вы оказались в контексте, у меня есть аквариум и много компонентов в нем (скажем, водоросли и рыба). Оба имеют возраст, но только рыбы имеют расу.
У меня есть класс для general_components (возраст и другие вещи) и класс для специфичных для рыб компонентов (раса, пол и т. Д.).
Я создал класс компонентов шаблона с помощью метода create, который выглядит следующим образом:
template<typename ConcreteComponent> // ConcreteComponent is attached to the class
ConcreteComponent& Components<ConcreteComponent>::create( entity e ) {
m_components.push_back( ConcreteComponent(e) );
return m_components.back();
}
Проблема, с которой я столкнулся, заключается в том, что я хочу иметь возможность вызывать разные конструкторы в зависимости от того, какой у меня класс (вместо сущности e прямо здесь, что является общим для каждого класса в моей настройке), но при этом оставаться наиболее эффективным способом (так с шаблонами и не копировать вставить для каждого класса). Для моей проблемы это не был бы конец света, но в целом, если бы я столкнулся с этим снова, я хочу быть готовым.
Есть ли способ вызвать функцию создания с другими параметрами?
Например:
A<fishComponents> myClassIter;
myClassIter.create("name", age, race, sex)
Для рыб пройдет "name",age,race,sex
в ConcreteComponent()
конструктор вместо только e
(А у меня есть "name",age,race,sex
конструктор для fishComponents
).
TL; DR: в методе класса шаблона можно передать другое число и характер значений в конструктор используемого класса в зависимости от параметров
template<typename A>
void myClass<A>::create( list_of_parameters) {
A(list_of_parameters) /*calls the constructor of the template class A */
}
Я видел что-то подобное в Си, но было рекомендовано не трогать его, так как оно было устаревшим и больше не использовалось.
Решение здесь заключается в использовании пакетов параметров и std::forward
передать любые аргументы, которые приходят к реальному конструктору. Полный, но упрощенный пример (без структур данных и одного аргумента на тип) приведен ниже:
#include <iostream>
class Fish {
public:
Fish(std::string const &name) {
std::cout << "Making a fish named " << name << '\n';
}
};
class Seaweed {
public:
Seaweed(int length) {
std::cout << "Making a seaweed that's " << length << " feet long\n";
}
};
template <typename ConcreteComponent, typename ...ARGS>
ConcreteComponent create(ARGS && ...args) {
return ConcreteComponent(std::forward<ARGS>(args)...);
}
int main() {
create<Fish>("Bob");
create<Seaweed>(42);
return 0;
}
Выход:
$ ./forwarding
Making a fish named Bob
Making a seaweed that's 42 feet long
Стоит прочитать о std::forward
, но то, что мы в основном делаем здесь, это взять все, что приходит к create
и передача его конструктору типа, а также сохранение свойств типа (например, является ли он временным или нет). Таким образом, вы можете пройти что-нибудь, до тех пор, пока есть действительный конструктор для передачи вещей.
Мой код был протестирован с g ++ — 7.3.0 с использованием C ++ 11, 14 и 17.
Вам лучше использовать наследование класса, которое используется в программировании Oriented-Object.
Создайте базовый класс и его унаследованные классы, чтобы объекты сгенерированных унаследованных классов могли динамически создавать свои различные свойства.