5

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.

0

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

3 Comments

A template alias to retrieve the type would go well with this solution.
@super Do you mean template alias inside if-constexpr or something else?
I was thinking template <unsigned I, typename... Ts> using Tail_t = decltype(Tail<I, Ts...>());
4

For Tail (why is it a function?), the approach can be almost the same as that of type_at. The only thing you have to change is the base case of the recursion:

template <typename ... Ts> struct types_from<0, Ts...> { using type = Base<Ts...>; // we don't like nasty typedef syntax }; 

Comments

2

And now, for something completely different...

Just for fun I propose a C++14 solution that doesn't use recursion but the power of std::tuple_cat().

#include <tuple> #include <type_traits> template <typename...> struct Base { }; template <std::size_t I, std::size_t J, typename A, std::enable_if_t<(I <= J), bool> = true> constexpr std::tuple<Base<A>> Tail_helper3 (); template <std::size_t I, std::size_t J, typename A, std::enable_if_t<(I > J), bool> = true> constexpr std::tuple<> Tail_helper3 (); template <typename ... As> constexpr Base<As...> Tail_helper2 (std::tuple<Base<As>...> const &); template <std::size_t I, typename ... As, std::size_t ... Is> constexpr auto Tail_helper1 (std::index_sequence<Is...> const &) -> decltype( Tail_helper2(std::tuple_cat(Tail_helper3<I, Is, As>()...)) ); template <std::size_t I, typename ... As> constexpr auto Tail () -> decltype( Tail_helper1<I, As...>(std::index_sequence_for<As...>{}) ) { static_assert(I < sizeof...(As), "index out of range"); return {}; } int main () { static_assert( std::is_same_v<Base<int, double, int>, decltype(Tail<0u, int, double, int>())> ); static_assert( std::is_same_v<Base<double, int>, decltype(Tail<1u, int, double, int>())> ); static_assert( std::is_same_v<Base<int>, decltype(Tail<2u, int, double, int>())> ); // Tail<3u, int, double, int>(); compilation error! } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.