Matthew
Matthew

Reputation: 850

Unpack parameter pack into std::initializer_list?

Is there any way to use a parameter pack to create an initializer list of objects or to insert objects into a std::vector? The problem I am having is all examples of parameter packs I have seen use passed arguments for the compiler to be able to differentiate which function it needs to call. The thing is that I have no arguments to pass to the functions just the types.

Example:

// compiler cannot determine which function is correct
namespace impl
{
    template<class T, class... U>
    void get_type_impl(std::vector<MetaClass*>& types)
    {
        // rusty::get<T>(); just retrieves a MetaClass object for the specified type
        types.emplace_back(rusty::get_type<T>());
        impl::get_type_impl<U...>(types);
    }

    template <class T>
    void get_type_impl(std::vector<MetaClass*>& types)
    {
        types.emplace_back(rusty::get_type<T>());
    }
}

template <class... T>
std::vector<MetaClass*> get_types()
{
    std::vector<MetaClass*> types;
    types.reserve(sizeof...(T));
    impl::get_type_impl<T...>(types);
    return types;
}

Example Usage:

auto types = get_types<MovementComponent, GraphicsComponent>();

Edit:

The goal is to create a vector of objects that are created from the provided template types. The current problem I have is that the compiler cannot deduce which function to use. As both get_type_impl can have the same function signature.

Solution:

namespace impl
{
    template <class T>
    void get_type_impl(std::vector<MetaClass*>& types)
    {
        types.emplace_back(rusty::get_type<T>());
    }
    template<class T0, class T1, class... Tn>
    void get_type_impl(std::vector<MetaClass*>& types)
    {
        types.emplace_back(rusty::get_type<T0>());
        impl::get_type_impl<T1, Tn...>(types);
    }
}

template <class... T>
std::vector<MetaClass*> get_types()
{
    std::vector<MetaClass*> types;
    types.reserve(sizeof...(T));
    impl::get_type_impl<T...>(types);
    return types;
}

The solution is to force one of the get_type_impl to take at least 2 template types and the other to simply take 1. This creates enough a difference in the signatures for the compiler to determine which is the correct function.

Upvotes: 1

Views: 859

Answers (1)

max66
max66

Reputation: 66200

Not sure to understand but... it seems to me that you'r looking for something as follows (caution: code not tested):

template <typename ... Ts>
std::vector<MetaClass*> get_types()
 { return { rusty::get_type<Ts>()... }; }

Otherwise, to solve the problem with get_types_impl(), I suggest to delete the second function

template <class T>
void get_type_impl(std::vector<MetaClass*>& types)
{
    types.emplace_back(rusty::get_type<T>());
}

and substitute it with the following ground case

template <int = 0>
void get_type_impl (std::vector<MetaClass*> const &)
 { }

The idea behind this is add (emplace_back()) elements in types through the first version of get_types_impl() and make so the last call, when the variadic type list U... is empty and is called

impl::get_type_impl<>(types);

, is hijacked (thanks the default not type template parameter int=0) to the ground case.

Upvotes: 3

Related Questions