Suppose I have a template which is parametrized by a class type and a number of argument types. a set of arguments matching these types are stored in a tuple. How can one pass these to a constructor of the class type?
In almost C++11 code:
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return T(get<0>(args), get<1>(args), ...); }
};
How can the ... in the constructor call be filled without fixing the length?
I guess I could come up with some complicated mechanism of recursive template calls which does this, but I can't believe that I'm the first to want this, so I guess there will be ready-to-use solutions to this out there, perhaps even in the standard libraries.
C++17 has std::make_from_tuple for this:
template <typename T, typename... Args>
struct foo
{
std::tuple<Args...> args;
T gen() { return std::make_from_tuple<T>(args); }
};
You need some template meta-programming machinery to achieve that.
The easiest way to realize the argument dispatch is to exploit pack expansion on expressions which contain a packed compile-time sequence of integers. The template machinery is needed to build such a sequence (also see the remark at the end of this answer for more information on a proposal to standardize such a sequence).
Supposing to have a class (template) index_range that encapsulates a compile-time range of integers [M, N) and a class (template) index_list that encapsulates a compile-time list of integers, this is how you would use them:
template<typename T, typename... Args>
struct foo
{
tuple<Args...> args;
// Allows deducing an index list argument pack
template<size_t... Is>
T gen(index_list<Is...> const&)
{
return T(get<Is>(args)...); // This is the core of the mechanism
}
T gen()
{
return gen(
index_range<0, sizeof...(Args)>() // Builds an index list
);
}
};
And here is a possible implementation of index_range and index_list:
//===============================================================================
// META-FUNCTIONS FOR CREATING INDEX LISTS
// The structure that encapsulates index lists
template <size_t... Is>
struct index_list
{
};
// Collects internal details for generating index ranges [MIN, MAX)
namespace detail
{
// Declare primary template for index range builder
template <size_t MIN, size_t N, size_t... Is>
struct range_builder;
// Base step
template <size_t MIN, size_t... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};
// Induction step
template <size_t MIN, size_t N, size_t... Is>
struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
{
};
}
// Meta-function that returns a [MIN, MAX) index range
template<unsigned MIN, unsigned MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;
Also notice, that an interesting proposal by Jonathan Wakely exists to standardize an int_seq class template, which is something very similar to what I called index_list here.
Use index_sequence to unpack a std::tuple (or std::pair, std::array, or anything else supporting the tuple interface):
#include <utility>
#include <tuple>
template <typename Tuple, std::size_t... Inds>
SomeClass help_make_SomeClass(Tuple&& tuple, std::index_sequence<Inds...>)
{
return SomeClass(std::get<Inds>(std::forward<Tuple>(tuple))...);
}
template <typename Tuple>
SomeClass make_SomeClass(Tuple&& tuple)
{
return help_make_SomeClass(std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
std::index_sequence and std::make_index_sequence will be in C++1y. If you can't find a header that defines them, you could use these:
template <std::size_t... Inds>
struct index_sequence {
static constexpr std::size_t size()
{ return sizeof...(Inds); }
};
template <std::size_t N, std::size_t... Inds>
struct help_index_seq {
typedef typename help_index_seq<N-1, N-1, Inds...>::type type;
};
template <std::size_t... Inds>
struct help_index_seq<0, Inds...> {
typedef index_sequence<Inds...> type;
};
template <std::size_t N>
using make_index_sequence = typename help_index_seq<N>::type;
Live example, in C++11 mode: http://coliru.stacked-crooked.com/a/ed91a67c8363061b
C++14 will add standard support for index_sequence:
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return gen_impl(std::index_sequence_for<Args...>()); }
private:
template <size_t... Indices>
T gen_impl(std::index_sequence<Indices...>) { return T(std::get<Indices>(args)...); }
};
You'll need to use the indices trick, which means a layer of indirection:
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return gen(build_indices<sizeof...(Args)>{}); }
private:
template<std::size_t... Is>
T gen(indices<Is...>) { return T(get<Is>(args)...); }
};
Create a sequence of indexes from 0 through n-1:
template<size_t... indexes>
struct seq {};
template<size_t n, size_t... indexes>
struct make_seq: make_seq<n-1, n-1, indexes...> {};
template<size_t... indexes>
struct make_seq: make_seq<0, indexes...> {
typedef seq<indexes...> type;
};
unpack them in parallel with your args, or as the index to get<> in your case.
The goal is something like:
template< typename T, typename Tuple, typename Indexes >
struct repack;
template< typename... Ts, size_t... indexes >
struct repack< tuple<Ts...>, seq<indexes...> > {
T operator()( tuple<Ts...> const& args ) const {
return T( get<indexes>(args)... );
}
};
use repack in your gen like this:
T gen() {
repack<T, tuple<Args...>, typename make_seq<sizeof...(Args)>::type> repacker;
return repacker( args );
}
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
It is possible to use template parameters pack as follows:
template <int T1, int... Ts>
struct Test {
static constexpr int sizes[] = {Ts...};
};
template <int T1, int... Ts>
constexpr int Test<T1, Ts...>::sizes[];
However, as it is detailed here, the template parameter pack must be the last template parameter. Hence, we cannot have a code such as this:
template <int T1, int... Ts, int Tn>
struct Test {
static constexpr int sizes[] = {Ts...};
Foo<Ts...> foo;
};
template <int T1, int... Ts, int Tn>
constexpr int Test<T1, Ts..., Tn>::sizes[];
In many cases, we need to have access to the last element of a set of template parameters. My question is, what's the best practice for realizing the above code?
Edit:
This is not duplicate of this question. I am trying to get everything except the last parameter (not the last parameter itself), since I need to define Foo as follows:
Foo<Ts...> foo;
You could go with the standard method of using std::index_sequence
template<template<auto...> typename Tmp, size_t... Is, typename... Args>
constexpr auto take_as(std::index_sequence<Is...>, Args...)
{
using Tup = std::tuple<Args...>;
return Tmp<std::tuple_element_t<Is, Tup>{}...>{};
}
template<auto... Vals>
struct except_last
{
template<template<auto...> typename Tmp>
using as = decltype(take_as<Tmp>(std::make_index_sequence<sizeof...(Vals) - 1>{},
std::integral_constant<decltype(Vals), Vals>{}...));
};
Which you use as
using F = except_last<1, 2, 3, 4>::as<Foo>; // F is Foo<1, 2, 3>
This is both easier to implement and read, but you potentially get O(n) instantiation depth. If you are obsessed with efficiency, you could do O(1) instantiation depth by abusing fold expressions
template<typename T>
struct tag
{
using type = T;
};
template<typename F, typename... Ts>
using fold_t = decltype((F{} + ... + tag<Ts>{}));
template<size_t N, typename... Ts>
struct take
{
template<typename T>
auto operator+(tag<T>) -> take<N - 1, Ts..., T>;
};
template<typename... Ts>
struct take<0, Ts...>
{
template<template<auto...> typename Tmp>
using as = Tmp<Ts{}...>;
template<typename T>
auto operator+(tag<T>) -> take<0, Ts...>;
};
template<auto... Vals>
struct except_last
{
template<template<auto...> typename Tmp>
using as = fold_t<take<sizeof...(Vals) - 1>,
std::integral_constant<decltype(Vals), Vals>...>::template as<Tmp>;
};
What's the most efficient way to access the last template parameter?
You could use a little helper to convert the parameter pack into an array.
template<int... Args>
struct pack {
static constexpr std::array as_array{ Args... };
};
You can then get the last argument with array indexing:
template <int T1, int... Ts>
struct Test {
static constexpr int last = pack<Ts...>::as_array[sizeof...(Ts) - 1];
integer_sequence is a way:
template <typename SeqN, typename Seq> struct TestImpl;
template <int... Ns, std::size_t ... Is>
struct TestImpl<std::integer_sequence<int, Ns...>, std::index_sequence<Is...>>
{
private:
using SeqTuple = std::tuple<std::integral_constant<int, Ns>...>;
public:
static constexpr int sizes[] = {std::tuple_element_t<Is, SeqTuple>::value...};
Foo<std::tuple_element_t<Is, SeqTuple>::value...> foo;
};
template <int N1, int N2, int... Ns> // At least 2 numbers
using Test = TestImpl<std::integer_sequence<int, N1, N2, Ns...>,
std::make_index_sequence<1 + sizeof...(Ns)>>;
Demo
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;
Suppose I have a template which is parametrized by a class type and a number of argument types. a set of arguments matching these types are stored in a tuple. How can one pass these to a constructor of the class type?
In almost C++11 code:
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return T(get<0>(args), get<1>(args), ...); }
};
How can the ... in the constructor call be filled without fixing the length?
I guess I could come up with some complicated mechanism of recursive template calls which does this, but I can't believe that I'm the first to want this, so I guess there will be ready-to-use solutions to this out there, perhaps even in the standard libraries.
C++17 has std::make_from_tuple for this:
template <typename T, typename... Args>
struct foo
{
std::tuple<Args...> args;
T gen() { return std::make_from_tuple<T>(args); }
};
You need some template meta-programming machinery to achieve that.
The easiest way to realize the argument dispatch is to exploit pack expansion on expressions which contain a packed compile-time sequence of integers. The template machinery is needed to build such a sequence (also see the remark at the end of this answer for more information on a proposal to standardize such a sequence).
Supposing to have a class (template) index_range that encapsulates a compile-time range of integers [M, N) and a class (template) index_list that encapsulates a compile-time list of integers, this is how you would use them:
template<typename T, typename... Args>
struct foo
{
tuple<Args...> args;
// Allows deducing an index list argument pack
template<size_t... Is>
T gen(index_list<Is...> const&)
{
return T(get<Is>(args)...); // This is the core of the mechanism
}
T gen()
{
return gen(
index_range<0, sizeof...(Args)>() // Builds an index list
);
}
};
And here is a possible implementation of index_range and index_list:
//===============================================================================
// META-FUNCTIONS FOR CREATING INDEX LISTS
// The structure that encapsulates index lists
template <size_t... Is>
struct index_list
{
};
// Collects internal details for generating index ranges [MIN, MAX)
namespace detail
{
// Declare primary template for index range builder
template <size_t MIN, size_t N, size_t... Is>
struct range_builder;
// Base step
template <size_t MIN, size_t... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};
// Induction step
template <size_t MIN, size_t N, size_t... Is>
struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
{
};
}
// Meta-function that returns a [MIN, MAX) index range
template<unsigned MIN, unsigned MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;
Also notice, that an interesting proposal by Jonathan Wakely exists to standardize an int_seq class template, which is something very similar to what I called index_list here.
Use index_sequence to unpack a std::tuple (or std::pair, std::array, or anything else supporting the tuple interface):
#include <utility>
#include <tuple>
template <typename Tuple, std::size_t... Inds>
SomeClass help_make_SomeClass(Tuple&& tuple, std::index_sequence<Inds...>)
{
return SomeClass(std::get<Inds>(std::forward<Tuple>(tuple))...);
}
template <typename Tuple>
SomeClass make_SomeClass(Tuple&& tuple)
{
return help_make_SomeClass(std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
std::index_sequence and std::make_index_sequence will be in C++1y. If you can't find a header that defines them, you could use these:
template <std::size_t... Inds>
struct index_sequence {
static constexpr std::size_t size()
{ return sizeof...(Inds); }
};
template <std::size_t N, std::size_t... Inds>
struct help_index_seq {
typedef typename help_index_seq<N-1, N-1, Inds...>::type type;
};
template <std::size_t... Inds>
struct help_index_seq<0, Inds...> {
typedef index_sequence<Inds...> type;
};
template <std::size_t N>
using make_index_sequence = typename help_index_seq<N>::type;
Live example, in C++11 mode: http://coliru.stacked-crooked.com/a/ed91a67c8363061b
C++14 will add standard support for index_sequence:
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return gen_impl(std::index_sequence_for<Args...>()); }
private:
template <size_t... Indices>
T gen_impl(std::index_sequence<Indices...>) { return T(std::get<Indices>(args)...); }
};
You'll need to use the indices trick, which means a layer of indirection:
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return gen(build_indices<sizeof...(Args)>{}); }
private:
template<std::size_t... Is>
T gen(indices<Is...>) { return T(get<Is>(args)...); }
};
Create a sequence of indexes from 0 through n-1:
template<size_t... indexes>
struct seq {};
template<size_t n, size_t... indexes>
struct make_seq: make_seq<n-1, n-1, indexes...> {};
template<size_t... indexes>
struct make_seq: make_seq<0, indexes...> {
typedef seq<indexes...> type;
};
unpack them in parallel with your args, or as the index to get<> in your case.
The goal is something like:
template< typename T, typename Tuple, typename Indexes >
struct repack;
template< typename... Ts, size_t... indexes >
struct repack< tuple<Ts...>, seq<indexes...> > {
T operator()( tuple<Ts...> const& args ) const {
return T( get<indexes>(args)... );
}
};
use repack in your gen like this:
T gen() {
repack<T, tuple<Args...>, typename make_seq<sizeof...(Args)>::type> repacker;
return repacker( args );
}