Пусть у нас есть некий аксессор:
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>()... );
	}
}