Шаблонные классы и вызов различных конструкторов в зависимости от итерации

Я изучаю 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 */
}

Я видел что-то подобное в Си, но было рекомендовано не трогать его, так как оно было устаревшим и больше не использовалось.

1

Решение

Решение здесь заключается в использовании пакетов параметров и 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.

2

Другие решения

Вам лучше использовать наследование класса, которое используется в программировании Oriented-Object.

Создайте базовый класс и его унаследованные классы, чтобы объекты сгенерированных унаследованных классов могли динамически создавать свои различные свойства.

1