Related
I am quite new to TMP world though I can easily understand the code but have problem writing new. I was given below question which I couldn't solve. Can someone help me understand how could I have done this.
Below is the description of the question
template<int... Xs> struct Vector;
It can be used like this:
Vector<1,2,3>
We want to write a function that takes multiple vectors, and zips then *.i.e. given input
Vector<1,2,3>, Vector<2,3,4>, Vector<3,4,5>
produce:
Vector<6,24,60>
A common way to implement this kind of computation statically is with a metafunction
template <typename... Vectors>
struct zip
{
using type = XXXX;
}
where XXXX is the logic of the zip. We could verify like so:
static_assert(
std::is_same<
zip<Vector<1, 2, 3>, Vector<2, 3, 4>, Vector<3, 4, 5>>::type,
Vector<6, 24, 60>>::value);
I would like to know, how to complete this logic, Thanks.
Here's a simple way to implement this zip metafunction in c++14 using partial template specializations:
template <int...> struct Vector;
template <typename...>
struct zip;
template <int... Is>
struct zip<Vector<Is...>> {
using type = Vector<Is...>;
};
template <int... Is, int... Js, typename... Vectors>
struct zip<Vector<Is...>, Vector<Js...>, Vectors...> {
using type = typename zip<Vector<(Is * Js)...>, Vectors...>::type;
};
Godbolt.org
You have chosen a rather non-trivial problem as your first attempt at template metaprogramming. Anyway, here's my take:
template<int... Xs> struct Vector;
template <int... Xs>
constexpr std::size_t vectorSize(Vector<Xs...>*) {
return sizeof...(Xs);
}
template <typename V>
constexpr std::size_t vectorSize() {
return vectorSize(static_cast<V*>(nullptr));
}
template <std::size_t I, int... Xs>
constexpr int getVal(Vector<Xs...>*) {
return std::get<I>(std::make_tuple(Xs...));
}
template <std::size_t I, typename V>
constexpr int getVal() {
return getVal<I>(static_cast<V*>(nullptr));
}
template <std::size_t I, typename... Vs>
constexpr int makeProd() {
return (getVal<I, Vs>() * ...);
}
template <typename... Vs, std::size_t... Is>
constexpr auto zipHelper(std::index_sequence<Is...>)
-> Vector<makeProd<Is, Vs...>()...>;
template <typename... Vs>
struct zip
{
static constexpr std::size_t size =
vectorSize<std::tuple_element_t<0, std::tuple<Vs...>>>();
static_assert(((vectorSize<Vs>() == size) && ...));
using type = decltype(zipHelper<Vs...>(std::make_index_sequence<size>{}));
};
Demo
I have a function foo that calls a function bar with a subset of types passed into foo's variadic template. For example:
template <typename... T>
void foo() {
// ...
template <size_t start_idx, typename... T>
using param_pack = /*Parameter pack with T[start_idx]...T[N]*/
auto b = bar<param_pack<2, T...>>();
// ...
}
Is there a way to extract a "sub-parameter pack". In the above case
if T = [int float char double] then param_pack<2, T...> = [char double]
[EDIT]
My goal is to be able to use something like this to match event handlers. For example
struct ev {};
template <typename... T>
struct event : ev {
std::tuple<T...> data_;
event(T&&... d) : data_(std::make_tuple(std::forward<T>(d)...)) {}
};
template <typename... Functor>
struct handler {
std::tuple<Functor...> funcs_;
handler(Functor&&... f) : funcs_(std::make_tuple(std::forward<Functor>(f)...)) {}
void handle_message(ev* e) {
auto ptrs = std::make_tuple(
dynamic_cast<event<param_pack<1, typename function_traits<F>::args>>*>(e)...
);
match(ptrs);
}
};
Here function_traits::args get a parameter pack for the function arguments and match iterates over the the tuple funcs_ checking if the dynamic_cast was successful and executing the first successful function. I already have these implemented.
The handlers are something like
[] (handler* self, <ARGS>) -> void {
// ...
}
I am essentially trying to get rid of the self argument.
Set aside the fact that it lacks a check on the index N for simplicity, here is a possible solution based on a function declaration (no definition required) and an using declaration:
template<std::size_t N, typename... T, std::size_t... I>
std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>
sub(std::index_sequence<I...>);
template<std::size_t N, typename... T>
using subpack = decltype(sub<N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
The good part of this approach is that you have not to introduce a new type designed around a tuple, then specialize it somehow iteratively.
It follows a minimal, working example that uses the code above:
#include<functional>
#include<tuple>
#include<cstddef>
#include<type_traits>
template<std::size_t N, typename... T, std::size_t... I>
std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>
sub(std::index_sequence<I...>);
template<std::size_t N, typename... T>
using subpack = decltype(sub<N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
int main() {
static_assert(std::is_same<subpack<2, int, float, char, double>, std::tuple<char, double>>::value, "!");
}
See a full example up and running on wandbox.
The extended version that includes a check on the index N would look like this:
template<std::size_t N, typename... T, std::size_t... I>
std::enable_if_t<(N < sizeof...(T)), std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>>
sub(std::index_sequence<I...>);
That is the type you can see in the first example once wrapped in a std::enable_if_t, nothing more. Again, declaration is enough, no definition required.
EDIT
If you want to use your own class template instead of an std::tuple, you can easily modify the code to do that:
#include<functional>
#include<tuple>
#include<cstddef>
#include<type_traits>
template<typename...>
struct bar {};
template<template<typename...> class C, std::size_t N, typename... T, std::size_t... I>
std::enable_if_t<(N < sizeof...(T)), C<std::tuple_element_t<N+I, std::tuple<T...>>...>>
sub(std::index_sequence<I...>);
template<template<typename...> class C, std::size_t N, typename... T>
using subpack = decltype(sub<C, N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
int main() {
static_assert(std::is_same<subpack<bar, 2, int, float, char, double>, bar<char, double>>::value, "!");
}
EDIT
According to the code added to the question, the solution above is still valid. You should just define your event class as it follows:
struct ev {};
template <typename>
struct event;
template <typename... T>
struct event<std::tuple<T...>>: ev {
// ...
};
This way, when you do this:
event<param_pack<1, typename function_traits<F>::args>>
You still get a tuple out of param_pack (that is the subpack using declaration in my example), but it matches the template partial specialization of event and the parameter pack is at your disposal as T....
This is the best you can do, for you cannot put a parameter pack in an using declaration. Anyway it just works, so probably it can solve your issue.
You may do something like:
template <std::size_t N, typename ... Ts> struct drop;
template <typename ... Ts>
struct drop<0, Ts...>
{
using type = std::tuple<Ts...>;
};
template <std::size_t N, typename T, typename ... Ts>
struct drop<N, T, Ts...>
{
using type = typename drop<N - 1, Ts...>;
};
// Specialization to avoid the ambiguity
template <typename T, typename... Ts>
struct drop<0, T, Ts...>
{
using type = std::tuple<T, Ts...>;
};
Here is a quick but not particularly reusable solution.
template <typename Pack, std::size_t N, std::size_t... Is>
void invoke_bar_impl(std::index_sequence<Is...>) {
bar<std::tuple_element_t<N + Is, Pack>...>();
}
template <std::size_t N, typename... Ts>
void invoke_bar() {
auto indices = std::make_index_sequence<sizeof...(Ts) - N>();
invoke_bar_impl<std::tuple<Ts...>, N>(indices);
}
I have to following problem:
template< size_t... N_i >
class A
{
// ...
};
template< size_t N, size_t... N_i >
A</* first N elements of N_i...*/> foo()
{
A</* first N elements of N_i...*/> a;
// ...
return a;
}
int main()
{
A<1,2> res = foo<2, 1,2,3,4>();
return 0;
}
Here, I want foo to have the return type A</* first N size_t of N_i...*/>, i.e., the class A which has as template arguments the first N elements of the parameter pack N_i.
Does anyone know how this can be implemented?
Here is the shortest solution that came to my mind (with two lines spent for an alias).
It follows a minimal, working example based on the code posted by the OP:
#include<functional>
#include<cstddef>
#include<utility>
#include<tuple>
template<std::size_t... V>
class A {};
template<std::size_t... V, std::size_t... I>
constexpr auto func(std::index_sequence<I...>) {
return A<std::get<I>(std::make_tuple(V...))...>{};
}
template<std::size_t N, std::size_t... V>
constexpr auto func() {
return func<V...>(std::make_index_sequence<N>{});
}
template<std::size_t N, std::size_t... V>
using my_a = decltype(func<N, V...>());
int main() {
A<1,2> res1 = func<2, 1, 2, 3, 4>();
// Or even better...
decltype(func<2, 1, 2, 3, 4>()) res2{};
// Or even better...
my_a<2, 1, 2, 3, 4> res3{};
}
This is a slight variation on #skypjack's answer that avoids using tuples:
template <size_t... N_i,size_t... M_i>
auto foo2(std::index_sequence<M_i...>)
{
constexpr size_t values[] = {N_i...};
return A<values[M_i]...>();
}
template <size_t N,size_t... N_i>
auto foo()
{
return foo2<N_i...>(std::make_index_sequence<N>());
}
The most direct subproblem is in the land of typelists:
template <class... Ts>
struct typelist {
using type = typelist;
static constexpr std::size_t size = sizeof...(Ts);
};
template <class T>
struct tag { using type = T; };
template <std::size_t N, class TL>
struct head_n {
using type = ???;
};
Now, head_n is just a matter of simple recursion - move an element from one list to another list N times starting from an empty list.
template <std::size_t N, class R, class TL>
struct head_n_impl;
// have at least one to pop from and need at least one more, so just
// move it over
template <std::size_t N, class... Ts, class U, class... Us>
struct head_n_impl<N, typelist<Ts...>, typelist<U, Us...>>
: head_n_impl<N-1, typelist<Ts..., U>, typelist<Us...>>
{ };
// we have two base cases for 0 because we need to be more specialized
// than the previous case regardless of if we have any elements in the list
// left or not
template <class... Ts, class... Us>
struct head_n_impl<0, typelist<Ts...>, typelist<Us...>>
: tag<typelist<Ts...>>
{ };
template <class... Ts, class U, class... Us>
struct head_n_impl<0, typelist<Ts...>, typelist<U, Us...>>
: tag<typelist<Ts...>>
{ };
template <std::size_t N, class TL>
using head_n = typename head_n_impl<N, typelist<>, TL>::type;
Going from this to your specific problem I leave as an exercise to the reader.
An alternate approach is via concatenation. Convert every element of a typelist<Ts...> into either a typelist<T> or a typelist<>, and then concat them all together. concat is straightforward:
template <class... Ts>
struct concat { };
template <class TL>
struct concat<TL>
: tag<TL>
{ };
template <class... As, class... Bs, class... Rest>
struct concat<typelist<As...>, typelist<Bs...>, Rest...>
: concat<typelist<As..., Bs...>, Rest...>
{ };
And then we can do:
template <std::size_t N, class TL, class = std::make_index_sequence<TL::size>>
struct head_n;
template <std::size_t N, class... Ts, std::size_t... Is>
struct head_n<N, typelist<Ts...>, std::index_sequence<Is...>>
: concat<
std::conditional_t<(Is < N), typelist<Ts>, typelist<>>...
>
{ };
template <std::size_t N, class TL>
using head_n_t = typename head_n<N, TL>::type;
The advantage of this latter approach is that concat can be replaced in C++17 by a fold-expression given an appropriate operator+:
template <class... As, class... Bs>
constexpr typelist<As..., Bs...> operator+(typelist<As...>, typelist<Bs...> ) {
return {};
}
which allows:
template <std::size_t N, class... Ts, std::size_t... Is>
struct head_n<N, typelist<Ts...>, std::index_sequence<Is...>>
{
using type = decltype(
(std::conditional_t<(Is < N), typelist<Ts>, typelist<>>{} + ... + typelist<>{})
);
};
This is fairly simple with Boost.Hana:
namespace hana = boost::hana;
template<size_t... vals>
auto make_a(hana::tuple<hana::integral_constant<size_t, vals>...>)
{
return A<vals...>{};
}
template<size_t N, size_t... vals>
auto foo(){
constexpr auto front = hana::take_front(
hana::tuple_c<size_t, vals...>,
hana::integral_c<size_t,N>
);
return detail::make_a(front);
}
live demo
You could also make use of variadic generic lambda expression and reusable helper structure to perform compile-time iteration:
#include <utility>
#include <tuple>
template <std::size_t N, class = std::make_index_sequence<N>>
struct iterate;
template <std::size_t N, std::size_t... Is>
struct iterate<N, std::index_sequence<Is...>> {
template <class Lambda>
auto operator()(Lambda lambda) {
return lambda(std::integral_constant<std::size_t, Is>{}...);
}
};
template <size_t... Is>
struct A { };
template <size_t N, size_t... Is>
auto foo() {
return iterate<N>{}([](auto... ps){
using type = std::tuple<std::integral_constant<std::size_t, Is>...>;
return A<std::tuple_element_t<ps, type>{}...>{};
});
}
int main() {
decltype(foo<3, 1, 2, 3, 4>()) a; // == A<1, 2, 3> a;
}
Unfortunately, such method requires to define additional Helper types
template< size_t... N_i >
class A
{
};
template <size_t... N_i>
struct Helper;
template <size_t... N_i>
struct Helper<0, N_i...>
{
typedef A<> type;
};
template <size_t N0, size_t... N_i>
struct Helper<1, N0, N_i...>
{
typedef A<N0> type;
};
template <size_t N0, size_t N1, size_t... N_i>
struct Helper<2, N0, N1, N_i...>
{
typedef A<N0, N1> type;
};
template< size_t N, size_t... N_i >
typename Helper<N, N_i...>::type foo()
{
typename Helper<N, N_i...>::type a;
return a;
}
I'm trying to split an index_sequence into two halves. For that, I generate an index_sequence with the lower half and use it to skip the leading elements on the full index_sequence. The following is a minimal test case that represents what I'm trying to achieve:
template <int ...I>
struct index_sequence {};
template <int ...I, int ...J>
void foo(index_sequence<I...>, index_sequence<I..., J...>)
{}
int main()
{
foo(index_sequence<0>{}, index_sequence<0, 1>{});
}
I've tried this with the latest versions of Clang, GCC and MSVC, and they all fail to deduce J.... Is this allowed by the standard? If not, why and what would be a good way to achieve my intent?
If what you want is to split a std::index_sequence instead of removing the common prefix of two std::index_sequences, I think you can benefit from an implementation of slice and using it to split a std::index_sequence into pieces.
I'm going to omit the implementation of std::index_sequence and friends, since you can refer to the paper, N3658, and a sample implementation here.
make_index_range
To implement slice, we'll use a helper called make_integer_range. We want a std::index_sequence generator which gives us [Begin, End) instead of [0, End). Leveraging std::make_integer_sequence, we get:
template <typename T, typename Seq, T Begin>
struct make_integer_range_impl;
template <typename T, T... Ints, T Begin>
struct make_integer_range_impl<T, std::integer_sequence<T, Ints...>, Begin> {
using type = std::integer_sequence<T, Begin + Ints...>;
};
/* Similar to std::make_integer_sequence<>, except it goes from [Begin, End)
instead of [0, End). */
template <typename T, T Begin, T End>
using make_integer_range = typename make_integer_range_impl<
T, std::make_integer_sequence<T, End - Begin>, Begin>::type;
/* Similar to std::make_index_sequence<>, except it goes from [Begin, End)
instead of [0, End). */
template <std::size_t Begin, std::size_t End>
using make_index_range = make_integer_range<std::size_t, Begin, End>;
slice
Since we don't have a std::get-like functionality for std::index_sequence or a variadic template pack, we just build a temporary std::array to get us std::get. Then explode the array with only the slice we want.
template <std::size_t... Indices, std::size_t... I>
constexpr decltype(auto) slice_impl(
std::index_sequence<Indices...>,
std::index_sequence<I...>) {
using Array = std::array<std::size_t, sizeof...(Indices)>;
return std::index_sequence<std::get<I>(Array{{Indices...}})...>();
}
template <std::size_t Begin, std::size_t End, std::size_t... Indices>
constexpr decltype(auto) slice(std::index_sequence<Indices...> idx_seq) {
return slice_impl(idx_seq, make_index_range<Begin, End>());
}
split_at
One example of using the slice we just built is to write a split_at function. We specify the index at which we want to split the std::index_sequence, and return a pair of std::index_sequences split at the given index.
template <std::size_t At, std::size_t... Indices>
constexpr decltype(auto) split_at(index_sequence<Indices...> idx_seq) {
return std::make_pair(slice<0, At>(idx_seq),
slice<At, sizeof...(Indices)>(idx_seq));
}
Examples of split_at:
static_assert(std::is_same<
decltype(split_at<2>(index_sequence<1, 4, 2>())),
std::pair<index_sequence<1, 4>, index_sequence<2>>>(), "");
static_assert(std::is_same<
decltype(split_at<1>(index_sequence<1, 4, 2, 3>())),
std::pair<index_sequence<1>, index_sequence<4, 2, 3>>>(), "");
14.8.2.5/9 ... If the template argument list of P contains a pack expansion that is not the last template argument, the entire template argument list is a non-deduced context...
Thus, when comparing index_sequence<I..., J...> with index_sequence<0, 1>{}, neither I... nor J... can be deduced.
To get suffix, you may use something like:
template<int ... I> struct get_suffix_helper {
template<int ... J> static index_sequence<J...> foo(index_sequence<I..., J...>);
};
template<typename T1, typename T2> struct get_suffix;
template<int ... Is1, int ... Is2>
struct get_suffix<index_sequence<Is1...>, index_sequence<Is2...>> :
public decltype(get_suffix_helper<Is1...>::foo(std::declval<index_sequence<Is2...>>())) {};
static_assert(std::is_base_of<index_sequence<>,
get_suffix<index_sequence<1, 2>,
index_sequence<1, 2>>>::value, "error");
static_assert(std::is_base_of<index_sequence<42>,
get_suffix<index_sequence<1, 2>,
index_sequence<1, 2, 42>>>::value, "error");
Or, with some error check:
template <typename T1, typename T2> struct get_suffix;
template<int ...Is>
struct get_suffix<index_sequence<>, index_sequence<Is...>>
{
typedef index_sequence<Is...> type;
static const bool valid = true;
};
template<int ...Is>
struct get_suffix<index_sequence<Is...>, index_sequence<>>
{
typedef void type;
static const bool valid = false;
};
template<>
struct get_suffix<index_sequence<>, index_sequence<>>
{
typedef index_sequence<> type;
static const bool valid = true;
};
template<int N, int ...Is, int... Js>
struct get_suffix<index_sequence<N, Is...>, index_sequence<N, Js...>>
{
typedef typename get_suffix<index_sequence<Is...>, index_sequence<Js...>>::type type;
static const bool valid = get_suffix<index_sequence<Is...>, index_sequence<Js...>>::valid;
};
template<int N1, int N2, int ...Is, int... Js>
struct get_suffix<index_sequence<N1, Is...>, index_sequence<N2, Js...>>
{
typedef void type;
static const bool valid = false;
};
static_assert(std::is_same<index_sequence<>,
get_suffix<index_sequence<1, 2>,
index_sequence<1, 2>>::type>::value, "error");
static_assert(!get_suffix<index_sequence<1, 2, 42>, index_sequence<1, 2>>::valid, "error");
static_assert(!get_suffix<index_sequence<0, 2, 1>, index_sequence<0, 1, 2>>::valid, "error");
static_assert(std::is_same<index_sequence<42>,
get_suffix<index_sequence<1, 2>,
index_sequence<1, 2, 42>>::type>::value, "error");
Not an answer, but a workaround: recursively trim off the leading elements a la:
template <typename, typename> struct remove_prefix;
template <std::size_t... I>
struct remove_prefix<index_sequence<>, index_sequence<I...>> {
using type = index_sequence<I...>;
};
template <std::size_t First, std::size_t... I, std::size_t... J>
struct remove_prefix<index_sequence<First, I...>,
index_sequence<First, J...>> {
using type = typename remove_prefix<index_sequence<I...>,
index_sequence<J...>>::type;
};
Demo at Coliru.
I needed to split an index_sequence into a head and tail at a particular point and this was the implementation that I came up with:
template<size_t N, typename Lseq, typename Rseq>
struct split_sequence_impl;
template<size_t N, size_t L1, size_t...Ls, size_t...Rs>
struct split_sequence_impl<N,index_sequence<L1,Ls...>,index_sequence<Rs...>> {
using next = split_sequence_impl<N-1,index_sequence<Ls...>,index_sequence<Rs...,L1>>;
using head = typename next::head;
using tail = typename next::tail;
};
template<size_t L1, size_t...Ls, size_t...Rs>
struct split_sequence_impl<0,index_sequence<L1,Ls...>,index_sequence<Rs...>> {
using tail = index_sequence<Ls...>;
using head = index_sequence<Rs...,L1>;
};
template<typename seq, size_t N>
using split_sequence = split_sequence_impl<N-1,seq,empty_sequence>;
template<typename seq, size_t N>
using sequence_head_t = typename split_sequence<seq,N>::head;
template<typename seq, size_t N>
using sequence_tail_t = typename split_sequence<seq,N>::tail;
Let us suppose that a std::tuple<some_types...> is given. I would like to create a new std::tuple whose types are the ones indexed in [0, sizeof...(some_types) - 2]. For instance, let's suppose that the starting tuple is std::tuple<int, double, bool>. I would like to obtain a sub-tuple defined as std::tuple<int, double>.
I'm quite new to variadic templates. As a first step I tried to write a struct in charge of storing the different types of the original std::tuple with the aim of creating a new tuple of the same kind (as in std::tuple<decltype(old_tuple)> new_tuple).
template<typename... types>
struct type_list;
template<typename T, typename... types>
struct type_list<T, types...> : public type_list<types...> {
typedef T type;
};
template<typename T>
struct type_list<T> {
typedef T type;
};
What I would like to do is something like:
std::tuple<type_list<bool, double, int>::type...> new_tuple // this won't work
And the next step would be of discarding the last element in the parameter pack. How can I access the several type's stored in type_list? and how to discard some of them?
Thanks.
Here is a way to solve your problem directly.
template<unsigned...s> struct seq { typedef seq<s...> type; };
template<unsigned max, unsigned... s> struct make_seq:make_seq<max-1, max-1, s...> {};
template<unsigned...s> struct make_seq<0, s...>:seq<s...> {};
template<unsigned... s, typename Tuple>
auto extract_tuple( seq<s...>, Tuple& tup ) {
return std::make_tuple( std::get<s>(tup)... );
}
You can use this as follows:
std::tuple< int, double, bool > my_tup;
auto short_tup = extract_tuple( make_seq<2>(), my_tup );
auto skip_2nd = extract_tuple( seq<0,2>(), my_tup );
and use decltype if you need the resulting type.
A completely other approach would be to write append_type, which takes a type and a tuple<...>, and adds that type to the end. Then add to type_list:
template<template<typename...>class target>
struct gather {
typedef typename type_list<types...>::template gather<target>::type parent_result;
typedef typename append< parent_result, T >::type type;
};
which gives you a way to accumulate the types of your type_list into an arbitrary parameter pack holding template. But that isn't required for your problem.
This kind of manipulation is fairly easy with an index sequence technique: generate an index sequence with two fewer indices than your tuple, and use that sequence to select fields from the original. Using std::make_index_sequence and return type deduction from C++14:
template <typename... T, std::size_t... I>
auto subtuple_(const std::tuple<T...>& t, std::index_sequence<I...>) {
return std::make_tuple(std::get<I>(t)...);
}
template <int Trim, typename... T>
auto subtuple(const std::tuple<T...>& t) {
return subtuple_(t, std::make_index_sequence<sizeof...(T) - Trim>());
}
In C++11:
#include <cstddef> // for std::size_t
template<typename T, T... I>
struct integer_sequence {
using value_type = T;
static constexpr std::size_t size() noexcept {
return sizeof...(I);
}
};
namespace integer_sequence_detail {
template <typename, typename> struct concat;
template <typename T, T... A, T... B>
struct concat<integer_sequence<T, A...>, integer_sequence<T, B...>> {
typedef integer_sequence<T, A..., B...> type;
};
template <typename T, int First, int Count>
struct build_helper {
using type = typename concat<
typename build_helper<T, First, Count/2>::type,
typename build_helper<T, First + Count/2, Count - Count/2>::type
>::type;
};
template <typename T, int First>
struct build_helper<T, First, 1> {
using type = integer_sequence<T, T(First)>;
};
template <typename T, int First>
struct build_helper<T, First, 0> {
using type = integer_sequence<T>;
};
template <typename T, T N>
using builder = typename build_helper<T, 0, N>::type;
} // namespace integer_sequence_detail
template <typename T, T N>
using make_integer_sequence = integer_sequence_detail::builder<T, N>;
template <std::size_t... I>
using index_sequence = integer_sequence<std::size_t, I...>;
template<size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;
#include <tuple>
template <typename... T, std::size_t... I>
auto subtuple_(const std::tuple<T...>& t, index_sequence<I...>)
-> decltype(std::make_tuple(std::get<I>(t)...))
{
return std::make_tuple(std::get<I>(t)...);
}
template <int Trim, typename... T>
auto subtuple(const std::tuple<T...>& t)
-> decltype(subtuple_(t, make_index_sequence<sizeof...(T) - Trim>()))
{
return subtuple_(t, make_index_sequence<sizeof...(T) - Trim>());
}
Live at Coliru.
Subrange from tuple with boundary checking, without declaring "helper classes":
template <size_t starting, size_t elems, class tuple, class seq = decltype(std::make_index_sequence<elems>())>
struct sub_range;
template <size_t starting, size_t elems, class ... args, size_t ... indx>
struct sub_range<starting, elems, std::tuple<args...>, std::index_sequence<indx...>>
{
static_assert(elems <= sizeof...(args) - starting, "sub range is out of bounds!");
using tuple = std::tuple<std::tuple_element_t<indx + starting, std::tuple<args...>> ...>;
};
Usage:
struct a0;
...
struct a8;
using range_outer = std::tuple<a0, a1, a2, a3, a4, a5, a6, a7, a8>;
sub_range<2, 3, range_outer>::tuple; //std::tuple<a2, a3, a4>
One way to do it is to recursively pass two tuples to a helper struct that takes the first element of the "source" tuple and adds it to the end of the another one:
#include <iostream>
#include <tuple>
#include <type_traits>
namespace detail {
template<typename...>
struct truncate;
// this specialization does the majority of the work
template<typename... Head, typename T, typename... Tail>
struct truncate< std::tuple<Head...>, std::tuple<T, Tail...> > {
typedef typename
truncate< std::tuple<Head..., T>, std::tuple<Tail...> >::type type;
};
// this one stops the recursion when there's only
// one element left in the source tuple
template<typename... Head, typename T>
struct truncate< std::tuple<Head...>, std::tuple<T> > {
typedef std::tuple<Head...> type;
};
}
template<typename...>
struct tuple_truncate;
template<typename... Args>
struct tuple_truncate<std::tuple<Args...>> {
// initiate the recursion - we start with an empty tuple,
// with the source tuple on the right
typedef typename detail::truncate< std::tuple<>, std::tuple<Args...> >::type type;
};
int main()
{
typedef typename tuple_truncate< std::tuple<bool, double, int> >::type X;
// test
std::cout << std::is_same<X, std::tuple<bool, double>>::value; // 1, yay
}
Live example.