Пусть у нас есть некий аксессор:
template< typename TComponent >
TComponent* const QueryComponent();
Пусть у нас есть, для простоты, некоторый обработчик:
void PerformWorkflow( A*, B*, C* );
Тут
A
,
B
и
C
- это типы компонентов.
Чтобы подружить обработчик с аксессором необходимых ему компонентов, понадобится самый простой
Parameter pack expansion.
template< typename... TComponents >
void ApplyComponents( void (*workflow)( TComponents*... ) )
{
workflow( QueryComponent<TComponents>()... );
}
Здесь можно посмотреть как работает пример этого кода.
В
комментарии я вижу несоответствие типа параметра функции для
each
и типа результата
get
. Стоит напомнить что разыменование
nullptr
, который может вернуть
get
, приводит к неопределенному поведению [
?].
Поэтому, если распаковку переписать на
*QueryComponent<TComponents>()...
, т.е. на лету разыменовывать полученные указатели, то перед запуском функции для твоей
entity
следует убедиться что у нее есть все необходимые компоненты. Такая проверка является необходимой для запуска систем в ECS, т.к. система должна обрабатывать только удовлетворяющие своим фильтрам сущности.
Для этого уже потребуется использовать
Fold expression из C++17.
template <typename... T>
void each(typename identity<std::function<void(T& ...)>>::type func)
{
for(auto &entity: m_entities)
{
if( !( (entity.HasComponent<T>() && ...) ) )
{
continue;
}
func( *entity.get<T>()... );
}
}