With reflection we might get a simple way to slice a parameter pack in the future. Until then the implementations I know of are not pretty.
A common technique is to use tuples and std::index_sequence
:
#include <type_traits>
#include <utility>
#include <tuple>
#include <iostream>
template<int N> struct B { B(int) {} };
template<int N> struct C { C() {} C(int) {} };
template<class ...Args>
int get_first(Args&&... args)
{
std::cout << "first: ";
((std::cout << args << ' '), ...) << std::endl;
return 0;
}
template<typename ...Args>
int get_last(Args&&... args)
{
std::cout << "second: ";
((std::cout << args << ' '), ...) << std::endl;
return 0;
}
template<std::size_t... Idx, class ...Args>
int get_first_impl(std::index_sequence<Idx...>, std::tuple<Args...> args)
{
return get_first(std::get<Idx>(args)...);
}
template<std::size_t Offset, std::size_t... Idx, class ...Args>
int get_last_impl(std::integral_constant<std::size_t, Offset>, std::index_sequence<Idx...>, std::tuple<Args...> args)
{
return get_last(std::get<Idx + Offset>(args)...);
}
template<int N>
struct A5
{
B<N> b;
C<5-N> c;
template<class ...Args>
A5(Args&&... args)
: b{get_first_impl(std::make_index_sequence<N>{},
std::tuple{args...})} ,
c{get_last_impl(std::integral_constant<std::size_t, N>{},
std::make_index_sequence<5 - N>{},
std::tuple{args...})}
{}
};
int main()
{
A5<3> a{1, 2, 3, 4, 5};
}
This will call get_first(1, 2, 3)
and get_last(4, 5)
respectively:
first: 1 2 3
second: 4 5
See it in action on godbolt.
The ideea is: we pack the tuple with the full args and send it along with the indexes we need for each function and then we get for the final args just the elements at the indexes we are interested in.
Here is a step by step expansion of what is happening:
get_first_impl(std::index_sequence<0, 1, 2>{}, std::tuple{1, 2, 3, 4, 5})
\/
get_first(std::get<0>(tp{1, 2, 3, 4, 4}),
std::get<1>(tp{1, 2, 3, 4, 4}),
std::get<2>(tp{1, 2, 3, 4, 4}),
\/
get_first(1, 2, 3)
get_last_impl(std::integral_constant<3>{},
std::index_sequence<0, 1>{}.
std::tuple{1, 2, 3, 4, 5})
\/
get_second(std::get<0 + 3>(tp{1, 2, 3, 4, 5},
std::get<1 + 3>(tp{1, 2, 3, 4, 5})
\/
get_second(std::get<3>(tp{1, 2, 3, 4, 5},
std::get<4>(tp{1, 2, 3, 4, 5})
\/
get_second(4, 5)
I think Boost.Hana has a pretty and simple way to do this, but I am not familiar with the library.