Search code examples
c++templatesvariadic-templates

How to return a type that mapped to variadic position


I'm enjoying learning about meta-programming, and started find out about some features, I can't make the call to at works which takes an index to return a type that mapped to varidiac position.

#include <iostream>
#include <type_traits>
#include <utility>

template <typename...>
struct type_list {};

template<typename T ,typename... Ns>
auto pop_front(type_list<T, Ns...> t) {
    return type_list<Ns...>{};
}

template<typename T ,typename... Ns>
auto front(type_list<T, Ns...> t) 
{
    return type_list<T>{};
}

template<typename T ,typename... Ns>
auto at(type_list<T, Ns...> t, size_t i)
{
    if (i) return at(pop_front(t), i-1);
    return front(t);
}

int main()
{
    type_list<int, bool, float> x;
    at(x,2);
}

Solution

  • If we move the index into the template paramters so that it becomes a compile time constant then we can leverage std::tuple_element to get the type at the supplied index like

    template<size_t Idx, typename... Ts>
    auto at(type_list<Ts...>)
    {
        return std::tuple_element_t<Idx, std::tuple<Ts...>>{};
    }
    

    and then we can call it like

    at<2>(x);
    

    It should be noted that this approach requires all types in the list to be default constructible.


    If you are only ever going to use at in a context like decltype(at<2>(x)) then you actually don't need to define the function and can instead use what I call a "meta function" like

    template<size_t Idx, typename... Ts>
    auto at(type_list<Ts...>t) -> std::tuple_element_t<Idx, std::tuple<Ts...>>;
    

    and now you can't run this function, but you can use it an any unevaluated context, like in decltype(at<2>(x)), and the types in the list do not need to be default constructible.