Тип возврата, который зависит от полей пакета статических параметров

Недавно я экспериментировал с пакетами параметров, так как они, кажется, заполняют довольно большую потребность в моей разработке. Однако я столкнулся с проблемой, для которой пакеты параметров кажутся реальным решением, но я не могу понять эту конкретную проблему. Проблема заключается в том, как взять каждый тип в пакете параметров, извлечь n-й элемент из статического поля этого типа и вернуть этот элемент (вместе с остальными) в кортеже. В случае, если эта формулировка была немного неясной, мой текущий вариант использования следующий:

/ * ВНИМАНИЕ: возможно, безвозмездная деталь * /

Архитектура моей программы — это архитектура Entity-Component System. По сути, существует несколько систем, которые определяют логику различных областей программы. Эти системы действуют на объекты, которые состоят из нескольких компонентов (которые содержат определенный фрагмент данных, например, DescriptionComponent). Каждая система проверит, что данный объект имеет все необходимые компоненты, а затем выполнит системную логику.

Для этого я создал компонентный базовый класс, из которого происходят определенные компоненты. Каждый производный компонент содержит статический вектор, который действует как менеджер для всех компонентов этого типа. Каждый компонент имеет поле entityId, которое ссылается на свою сущность-владельца, и статический вектор сортируется по этому идентификатору.

В настоящее время в данной системе я могу находить применимые объекты, просматривая компоненты, которые требуются системе, затем находя наборы компонентов, которые содержат один и тот же entityId, и выполняя логику для этих компонентов. Тем не менее, я делаю логику, чтобы перебирать статические векторы компонентов вручную на этом этапе, так как у каждой системы будут разные требования с точки зрения типов компонентов.

Быстрый пример, на случай, если вышеизложенное не было ясно:

Скажем, DisplaySystem требует PictureComponent и PositionComponent. Теперь скажите, что статические поля, управляющие этими типами, выглядят следующим образом:

PictureComponent::elements = [(picture: "somePic.jpg", id: 1), (picture: "otherPic.jpg", id: 2)]
PositionComponent::elements = [(pos: (1,2), id: 2), (pos: (4,5), id: 3)]

В настоящее время каждый компонент имеет свой собственный итератор. Начиная с нуля, мы увеличиваем индекс компонента с наименьшим значением entityId (поскольку векторы отсортированы по этому ключу). В приведенном выше примере мы попробуем index (0,0), увидим, что id 1 меньше id 2, поэтому увеличьте первый индекс. Затем мы попробуем (1,0), увидим, что оба компонента имеют entityId 2, и передадим их в систему в виде пары для выполнения логики. Затем мы увеличим оба индекса, попробуем (2,1) и выйдем за пределы вектора PictureComponent, и все будет готово.

/ * КОНЕЦ БЕСПЛАТНАЯ деталь * /

Решением, которое я мог бы представить для этой проблемы, был бы один шаблонный класс пакета параметров, который принимает требуемые типы компонентов и выводит кортежи компонентов, все сущности которых совпадают. Псевдокод для этого будет следующим

template <typename... RequiredComponentTypes>
class ComponentIterator {
/* standard input iterator functionality*/
...

array componentIndices // same size as our param pack, one index per type

tuple<RequiredComponentTypes...> getNextSetOfComponents() {
while every component's entity id is not equal:
find the currently indexed component with the lowest entity id;
increment the current index of that component type;

out of the while, once we have a set of components with the same entity id:
return a tuple of the indexed components for each type. **//this is the part I have no idea how to do**
}
}

Как отмечено в коде, процесс возврата кортежа, значения которого извлекаются из индекса в статическое поле типов, является частью, в которой я не уверен. Для любого числа параметров шаблона это легко сделать вручную (если у меня есть набор именованных параметризованных типов, то создание кортежа так же просто, как вызов make_tuple с соответствующими значениями.) Однако при работе с пакетом параметров я Я не уверен, как обойти эту проблему.

Буду очень признателен за любую помощь, которую вы можете предложить, и если вам нужны какие-либо разъяснения или более подробная информация, пожалуйста, не стесняйтесь, дайте мне знать. Спасибо!

1

Решение

Вы можете сделать что-то вроде:

template <typename... Ts>
class ComponentIterator {
static constexpr std::size_t size = sizeof...(Ts);

public:
ComponentIterator() : indices(), finished(false) { adjust(); }

std::tuple<Ts&...> get()
{
return get(std::index_sequence_for<Ts...>());
}

ComponentIterator& operator ++()
{
for (auto& e : indices) {
++e;
}
adjust();
return *this;
}

bool is_finished() const { return finished; }
private:
void adjust()
{
adjust(std::index_sequence_for<Ts...>());
}

template <std::size_t...Is>
std::tuple<Ts&...> get(std::index_sequence<Is...>)
{
return std::tie(Ts::elements[indices[Is]]...);
}

template <std::size_t...Is>
void adjust(std::index_sequence<Is...>) {
bool is_ended[size] = {indices[Is] == Ts::elements.size()...};
if (std::any_of(std::begin(is_ended), std::end(is_ended),
[](bool b) { return b; })) {
finished = true;
return;
}

int min_value = std::min({Ts::elements[indices[Is]].id...}) - 1;
for (;;)
{
++min_value;
bool increases[size] = {increase_until<Ts>(indices[Is], min_value)...};
if (std::any_of(std::begin(increases), std::end(increases),
[](bool b) { return !b; })) {
finished = true;
return;
}
const int ids[size] = {Ts::elements[indices[Is]].id...};
if (std::all_of(std::begin(ids), std::end(ids),
[min_value](int id) { return id == min_value;})) {
return;
}
}
}

template <typename T>
bool increase_until(std::size_t& index, int min_value)
{
for (; index != T::elements.size(); ++index) {
if (min_value <= T::elements[index].id) {
return true;
}
}
return false;
}
private:
std::array<std::size_t, size> indices;
bool finished;
};

Живой пример

0

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


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector