mardi 2 avril 2019

How to use and access a template parameter pack of paramter packs

Short Intro

I am trying to create a AddComponents() method that creates and adds multiple components to an entity at once. I have already written a working method to add one component at a time.

It has the following signature:

template <class TComponent, typename... TArguments>
TComponent & AddComponent(TArguments&&... arguments);

and is used in the following way

entity.AddComponent<SomeComponent>(data1, data2, data3);

I would now like to make a function that adds multiple components at one i.e. takes a parameter pack of TComponents. Of course, the data must be passed as well and here is where things get ugly; I basically need a parameter pack of parameter packs. The function should then iterate over the TComponents (e.g. using int i < sizeof...(Types)) and call AddComponent<T>(data...) for each TComponent. I have worked with templates quite a bit but I struggle to get my head around this.

What I want

Ideally, I want it to be used something like this:

entity.AddComponents<PositionComponent, SpriteComponent, TComponent>(
{ position },
{ texture, colour },
{ data1, data2 });

Internally I need a way to do something like

for each TComponent : TComponents
{
    this->AddComponent<TComponent>(forward...(data))
}

In theory, I might be able to get away without this but it seems like an interesting problem nevertheless.

AddComponent Code

In case people might question what the function does here's the code.

template <class TComponent, typename... TArguments>
inline TComponent & Entity::AddComponent(TArguments&&... arguments)
{
    auto typeId = detail::GetComponentTypeID<TComponent>();

    auto component = std::make_shared<TComponent>(eventManager, *this, std::forward<TArguments>(arguments)...);

    componentList.push_back(component);
    componentDictionary.insert(std::make_pair(typeId, component));

    entityManager.AddEntityToGroup(*this, typeId);

    this->AddPolymorphism(typeId, component);
    eventManager.RaiseEvent(mbe::event::ComponentsChangedEvent(*this));

    return *component;
}

Aucun commentaire:

Enregistrer un commentaire