Search code examples
c++variadic-templatestemplate-meta-programming

Take tail of variadic template parameters


Given this type:

template<typename ...As>
struct Base {};

I need to implement a function

template<int i, typename ...As>
constexpr auto Tail() {
   static_assert(i < sizeof...(As), "index out of range");
   return ??;
}

which returns an instance of B using the tail of type parameter list from index i.

For example,

Tail<0, int, float, double>() -> Base<int, float, double>
Tail<1, int, float, double>() -> Base<float, double>
Tail<2, int, float, double>() -> Base<double>
Tail<3, int, float, double>() -> fails with static assert

I know how to get the type at index i :

template <int64_t i, typename T, typename... Ts>
struct type_at
{
    static_assert(i < sizeof...(Ts) + 1, "index out of range");
    typedef typename type_at<i - 1, Ts...>::type type;
};

template <typename T, typename... Ts> struct type_at<0, T, Ts...> {
    typedef T type;
};

but I can't get a working version for the entire problem.


Solution

  • If you don't mind using C++17. Even static_assert is not needed:

    template<unsigned i, typename T, typename ...Ts>
    constexpr auto Tail() {
        if constexpr (i == 0)
            return Base<T, Ts...>();
        else 
            return Tail<i - 1, Ts...>();
    }
    
    
    int main(){
        Base<int, double, int> a = Tail<0, int, double, int>();    
        Base<double, int> b = Tail<1, int, double, int>();
        Base<int> c = Tail<2, int, double, int>();
        auto d = Tail<3, int, double, int>();
    }
    

    Btw, changed int to unsigned to avoid possibility of (nearly) infinite recursion for negative numbers.