I'm having problems creating a push_back
function for an std::vector
of std::variants
. This is a minimal implementation of my struct so far:
template<class T, class Ts...> //Must construct with at least 1 argument
struct entity_container
{
entity_container(T arg1, Ts ...args) //constructor, populate vector of std::variant's
{
entities.push_back(std::forward<decltype(arg1)>(arg1));
auto loop = [&](auto&& arg)
{
entities.push_back(std::forward<decltype(arg)>(arg));
}
(loop(args),...);
}
std::vector<std::variant<T, Ts...>> entities;
}
Now suppose I want to add a push_back
function then there are some things I considered:
if we are adding a type which already exists in the
std::variant
ofentity_container::entities
then we can simply use:entities.push_back(entity)
if we are adding a new type to
entity_container::entities
then we need to extended the type of thestd::variant
, then create a newstd::vector
of said type and move all the elements from the old vector to the new one.
for this second case, I came across two posts:
extending a variant type in c++ and copy/move elements between two std::variants
So using these tools this is what I wanted to do for my push_back
implementation:
template<typename E>
void push_back(E&& entity)
{
if( /* E is a new type to the variant */)
{
//std::variant<Old..., New> = std::variant<Old...> + New
using extended_type = t_variant_cat_t<std::remove_reference_t<decltype(Entities[0])>,
std::remove_reference_t<E>>;
//construct (with the new element) a new entity_container with the extended type,
entity_container<extended_type> entities_new(entity);
//move the entities from the old container to the new one
for(auto& ent : Entities)
entities_new.entities.push_back(std::move(ent)); //all entities are moveable types
//update replace the old container with the new
entities = entities_new;
}
else /* E is not a new type to the variant */
{
entities.push_back(entity);
}
}
But there are many, many problems with this.
How can we check that the type
E
is a new type to the variant?extended_type
would be something along the lines ofstd::variant<T1, T2, T3, T4>
but in reality we have to construct anentity_container
asentity_container<T1, T2, T3, T4>
- how can we convert from anstd::variant
to a type pack?when we do
entities = entities_new
at the end, these two objects have different types and therefore cannot be assigned to one another (and that's even if (2) could be fixed)Finally, we have to reconstruct the container every single time an element is pushed back. That's gonna be really slow.
So my overall question is, does anyone have any ideas to fix the above problems, or perhaps a whole new approach to writing this function.
Side Note, the structure is used as so:
template<class T>
struct Entity{};
Entity<A> entity_a;
Entity<B> entity_b;
Entity<C> entity_c;
entity_container c(entity_a, entity_b);
c.push_back(entity_c);