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);
}
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.