Loop on variadic templates types at runtime

I migrate a code from C++11 to C++17. In that code I do something like this (non-valid) code:

template <typename... Ts>
std::vector<std::size_t> store_types()
{
    std::vector<std::size_t> t;
    for(typename T : Ts)
        t.push_back(typeid(T).hash_code());
    return t;
}

For the moment, my implementation is the following:

template <typename Unused>
void add_types_in(std::vector<std::size_t>&)
{}

template <typename Unused, typename First, typename... Others>
void add_types_in(std::vector<std::size_t>& t)
{
    t.push_back(typeid(First).hash_code());
    add_types_in<Unused, Others...>(t);
}

template <typename... Ts>
std::vector<std::size_t> store_types()
{
    std::vector<std::size_t> t;
    add_types_in<void*, Ts...>(t);
    return t;
}

I see a lot a variadic functionalities in C++17, but there is a lot of things I don’t understand yet. Is there something more elegant (aka more "one-line") in C++17 than my implementation ? Maybe something similar to fold expressions ?

>Solution :

std::vector can be initialized with a list of values so you can just expand the pack directly in a braced-init-list like:

template <typename... Ts>
std::vector<std::size_t> store_types()
{
    return { typeid(Ts).hash_code()... };
}

If you want to avoid dynamic allocation, you can switch to use a std::array like:

// C++11 or 14
template <typename... Ts>
auto store_types() -> std::array<std::size_t, sizeof...(Ts)>
{
    return { typeid(Ts).hash_code()... };
}

// or
// C++17
template <typename... Ts>
auto store_types()
{
    return std::array{ typeid(Ts).hash_code()... };
}

Leave a Reply