Convert scalar + std::array + std::tuple into a big tuple - c++

Consider the following code:
template <class Scalar, class Array, class Tuple>
class Test {};
where Array is a std::array, and Tuple is a std::tuple. In this class, I will have a lot of SFINAE, and I would like to create a big tuple called Types that will contain the complete list of types. This will allow me to test some conditions with variadic lists.
So the challenge is to create a type that will have the following behaviour. If:
Scalar = int
Array = std::array<double, 3>
Tuple = std::tuple<char, float, std::string>
Then:
Types = std::tuple<int, double, double, double, char, float, std::string>
which is the concatenation of the internal data of the Scalar, Array and Tuple.
How to do that ?

This seems to work:
template<typename T1, typename T2>
struct concat_tuples;
template<typename... T1, typename... T2>
struct concat_tuples<std::tuple<T1...>, std::tuple<T2...>>
{
using type = std::tuple<T1..., T2...>;
};
// n_tuple<int, 3>::type == std::tuple<int, int, int>
template<typename T, size_t n>
struct n_tuple;
template<typename T>
struct n_tuple<T, 0>
{
using type = std::tuple<>;
};
template<typename T, size_t n>
struct n_tuple
{
using type = typename concat_tuples<
typename n_tuple<T, n-1>::type,
std::tuple<T>
>::type;
};
template <class Scalar, class Array, class Tuple>
struct Test;
template <class Scalar, typename T, size_t n, typename... Ts>
struct Test<Scalar, std::array<T, n>, std::tuple<Ts...>>
{
using type = typename concat_tuples<
typename concat_tuples<
std::tuple<Scalar>,
typename n_tuple<T, n>::type
>::type,
std::tuple<Ts...>
>::type;
};
Live demo here.

Use a partial specialization to deduce the types, and Xeo's tuple_cat comment to put them together (Live at Coliru:
template <typename ArrayType, std::size_t ArraySize, typename... Fields>
struct ArrayTuple : ArrayTuple<ArrayType, ArraySize-1, ArrayType, Fields...> {};
template <typename ArrayType, typename... Fields>
struct ArrayTuple<ArrayType, 0, Fields...> {
using type = std::tuple<Fields...>;
};
template <typename, typename, typename> class Test;
template <typename Scalar, typename ArrayType, std::size_t ArraySize, typename... Fields>
class Test<Scalar, std::array<ArrayType, ArraySize>, std::tuple<Fields...>> {
public:
// Modified tuple_cat code from Xeo's comment:
using Tuple = std::tuple<Fields...>;
using Types = decltype(
std::tuple_cat(std::tuple<Scalar>(),
typename ArrayTuple<ArrayType, ArraySize>::type(),
std::declval<Tuple>()));
};

Related

Subset a Variadic template given a constexpr boolean selection function

Suppose we have a variadic templated class like
template<class...Ts>
class X{
template<size_t I>
constexpr bool shouldSelect();
std::tuple<TransformedTs...> mResults; // this is want I want eventually
};
where the implementation of shouldSelect is not provided, but what it does is that, given an index i referring to the ith element of the variadic Ts, tells you whether we should select it to the subset.
I want to do a transformation on Ts such that only classes Ts at indexes that results in shouldSelect returning true should be selected. Is there an easy way to do this?
For example, if shouldSelect returns true for I = 1,2,4, and Ts... = short, int, double, T1, T2, then I want to get a TransformedTs... that is made up of int, double, T2. Then I can use this TransformedTs... in the same class.
If you're able to use C++17, this is pretty easy to implement using a combination of if constexpr and expression folding.
Start with some helper types, one with parameters to track the arguments to X::shouldSelect<I>(), and the other with a type to test.
template <typename T, size_t I, typename...Ts>
struct Accumulator {
using Type = std::tuple<Ts...>;
};
template <typename T>
struct Next { };
Then an operator overload either adds the type to the accumulator, or not with if constexpr:
template <typename TAcc, size_t I, typename... Ts, typename TArg>
decltype(auto) operator +(Accumulator<TAcc, I, Ts...>, Next<TArg>) {
if constexpr (TAcc::template shouldSelect<I>()) {
return Accumulator<TAcc, I + 1, Ts..., TArg>{};
} else {
return Accumulator<TAcc, I + 1, Ts...>{};
}
}
Finally, you can put it all together with a fold expression and extract the type with decltype:
template <template <typename... Ts> class T, typename... Ts>
constexpr decltype(auto) FilterImpl(const T<Ts...>&) {
return (Accumulator<T<Ts...>, 0>{} + ... + Next<Ts>{});
}
template<typename T>
using FilterT = typename decltype(FilterImpl(std::declval<T>()))::Type;
Usage:
using Result = FilterT<X<int, double, bool, etc>>;
Demo: https://godbolt.org/z/9h89zG
If you don't have C++17 available to you, it's still possible. You can do the same sort of conditional type transfer using a recursive inheritance chain to iterate though each type in the parameter pack, and std::enable_if to do the conditional copy. Below is the same code, but working in C++11:
// Dummy type for copying parameter packs
template <typename... Ts>
struct Mule {};
/* Filter implementation */
template <typename T, typename Input, typename Output, size_t I, typename = void>
struct FilterImpl;
template <typename T, typename THead, typename... TTail, typename... OutputTs, size_t I>
struct FilterImpl<T, Mule<THead, TTail...>, Mule<OutputTs...>, I, typename std::enable_if<( T::template shouldSelect<I>() )>::type >
: FilterImpl<T, Mule<TTail...>, Mule<OutputTs..., THead>, (I + 1)>
{ };
template <typename T, typename THead, typename... TTail, typename... OutputTs, size_t I>
struct FilterImpl<T, Mule<THead, TTail...>, Mule<OutputTs...>, I, typename std::enable_if<( !T::template shouldSelect<I>() )>::type >
: FilterImpl<T, Mule<TTail...>, Mule<OutputTs...>, (I + 1)>
{ };
template <typename T, typename... OutputTs, size_t I>
struct FilterImpl<T, Mule<>, Mule<OutputTs...>, I>
{
using Type = std::tuple<OutputTs...>;
};
/* Helper types */
template <typename T>
struct Filter;
template <template <typename... Ts> class T, typename... Ts>
struct Filter<T<Ts...>> : FilterImpl<T<Ts...>, Mule<Ts...>, Mule<>, 0>
{ };
template <typename T>
using FilterT = typename Filter<T>::Type;
Demo: https://godbolt.org/z/esso4M

Creating a new boost-variant type from given nested boost-variant type

Assume that I have a nested boost::variant-type TNested containing some types and some other boost::variant types (that itself cannot contain again boost::variant types, so that there will be no recursion).
I'm looking for a template alias flatten<TNested> that would evaluate to a boost::variant type have no nested boost::variants, e.g. TFlatten, whereas possible duplicate types are being removed, e.g. int occurs only once.
I have really no idea, if this can be accomplished somehow.
#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <iostream>
struct Person;
typedef boost::variant<int, double, boost::variant<std::string, int>, boost::variant<Person>> TNested;
typedef boost::variant<int, double, std::string, Person> TFlatten;
template<typename NestedVariant>
using flatten = //???
int main() {
flatten<TNested> x;
std::cout << typeid(x) == typeid(TFlatten) << std::endl;
}
wandbox example
Here's a valid C++11 recursive template-based solution that works with your example:
using nested = variant<int, double, variant<std::string, int>, variant<Person>>;
using flattened = variant<int, double, std::string, int, Person>;
static_assert(std::is_same<flatten_variant_t<nested>, flattened>{}, "");
General idea:
std::tuple is used as a generic type list and std::tuple_cat is used to concatenate type lists.
A flatten_variant<TResult, Ts...> recursive metafunction is defined which does the following:
TResult will get filled with flattened types and will be returned at the end of the recursion.
The recursion ends when Ts... is empty.
Non-variant types are appended to TResult.
Variant-types are unpacked, and all their inner types are recursively flattened, then appended to TResult.
Implementation:
namespace impl
{
// Type of the concatenation of all 'Ts...' tuples.
template <typename... Ts>
using cat = decltype(std::tuple_cat(std::declval<Ts>()...));
template <typename TResult, typename... Ts>
struct flatten_variant;
// Base case: no more types to process.
template <typename TResult>
struct flatten_variant<TResult>
{
using type = TResult;
};
// Case: T is not a variant.
// Return concatenation of previously processed types,
// T, and the flattened remaining types.
template <typename TResult, typename T, typename... TOther>
struct flatten_variant<TResult, T, TOther...>
{
using type = cat<TResult, std::tuple<T>,
typename flatten_variant<TResult, TOther...>::type>;
};
// Case: T is a variant.
// Return concatenation of previously processed types,
// the types inside the variant, and the flattened remaining types.
// The types inside the variant are recursively flattened in a new
// flatten_variant instantiation.
template <typename TResult, typename... Ts, typename... TOther>
struct flatten_variant<TResult, variant<Ts...>, TOther...>
{
using type =
cat<TResult, typename flatten_variant<std::tuple<>, Ts...>::type,
typename flatten_variant<TResult, TOther...>::type>;
};
template<typename T>
struct to_variant;
template<typename... Ts>
struct to_variant<std::tuple<Ts...>>
{
using type = variant<Ts...>;
};
}
template <typename T>
using flatten_variant_t =
typename impl::to_variant<
typename impl::flatten_variant<std::tuple<>, T>::type
>::type;
The problem with boost::variant is that it isn't the real variadic template only simulating one by adding a number of template parameters with default value boost::detail::variant::void_. To work with it as with variadic template, one need to change it first to the pack with relevant types. The full c++11 ready to use approach to do what you want could look as follows. The approach takes into account both flatness as well as uniqueness assumption to the result type. The integer_sequence part will be unnecessary if you decide to use c++14:
#include <boost/variant.hpp>
#include <tuple>
#include <type_traits>
template <class T, T... Vs>
struct integer_sequence { };
template <class T, class, class, class = integer_sequence<T>, class = integer_sequence<T, 0>, class = void>
struct make_integer_sequence_impl;
template <class T, T ICV1, T... Res, T... Pow>
struct make_integer_sequence_impl<T, std::integral_constant<T, ICV1>, std::integral_constant<T, 0>, integer_sequence<T, Res...>, integer_sequence<T, Pow...>, typename std::enable_if<(ICV1 > 0)>::type>: make_integer_sequence_impl<T, std::integral_constant<T, ICV1/2>, std::integral_constant<T, ICV1%2>, integer_sequence<T, Res...>, integer_sequence<T, Pow..., (Pow + sizeof...(Pow))...>> { };
template <class T, T ICV1, T... Res, T... Pow>
struct make_integer_sequence_impl<T, std::integral_constant<T, ICV1>, std::integral_constant<T, 1>, integer_sequence<T, Res...>, integer_sequence<T, Pow...>, void>: make_integer_sequence_impl<T, std::integral_constant<T, ICV1/2>, std::integral_constant<T, ICV1%2>, integer_sequence<T, Pow..., (Res + sizeof...(Pow))...>, integer_sequence<T, Pow..., (Pow + sizeof...(Pow))...>> { };
template <class T, class Res, class Pow>
struct make_integer_sequence_impl<T, std::integral_constant<T, 0>, std::integral_constant<T, 0>, Res, Pow, void> {
using type = Res;
};
template <class T, T V>
using make_integer_sequence = typename make_integer_sequence_impl<T, std::integral_constant<T, V/2>, std::integral_constant<T, V%2>>::type;
template <class>
struct is_variant_void {
static constexpr size_t value = 0;
};
template <>
struct is_variant_void<boost::detail::variant::void_> {
static constexpr size_t value = 1;
};
constexpr size_t sum(size_t v){
return v;
}
template <class... Args>
constexpr size_t sum(size_t v, Args... vs){
return v + sum(vs...);
}
template <class Variant>
struct variant_size;
template <class... Ts>
struct variant_size<boost::variant<Ts...>> {
static constexpr size_t value = sizeof...(Ts) - sum(is_variant_void<Ts>::value...);
};
template <class...>
struct pack { };
template <class V, class=make_integer_sequence<size_t, variant_size<V>::value>>
struct variant_to_pack;
template <class... Ts, size_t... Is>
struct variant_to_pack<boost::variant<Ts...>, integer_sequence<size_t, Is...>> {
using type = pack<typename std::tuple_element<Is, std::tuple<Ts...>>::type...>;
};
template <class>
struct unique_opaque { };
template <class... Ts>
struct unique_pack: unique_opaque<Ts>... { };
template <class, class, class = void>
struct unique;
template <class... Res, class T, class... Ts>
struct unique<unique_pack<Res...>, pack<T, Ts...>, typename std::enable_if<std::is_base_of<unique_opaque<T>, unique_pack<Res...>>::value>::type>:
unique<unique_pack<Res...>, pack<Ts...>> { };
template <class... Res, class T, class... Ts>
struct unique<unique_pack<Res...>, pack<T, Ts...>, typename std::enable_if<!std::is_base_of<unique_opaque<T>, unique_pack<Res...>>::value>::type>:
unique<unique_pack<Res..., T>, pack<Ts...>> { };
template <class... Res>
struct unique<unique_pack<Res...>, pack<>, void> {
using type = boost::variant<Res...>;
};
template <class...>
struct flatten;
template <class... Res, class T, class... Rest>
struct flatten<pack<Res...>, T, Rest...>: flatten<pack<Res..., T>, Rest...> { };
template <class... Res, class... Vs, class... Rest>
struct flatten<pack<Res...>, boost::variant<Vs...>, Rest...>: flatten<pack<Res...>, typename variant_to_pack<boost::variant<Vs...>>::type, Rest...> {};
template <class... Res, class... Vs, class... Rest>
struct flatten<pack<Res...>, pack<Vs...>, Rest...>: flatten<pack<Res...>, Vs..., Rest...> { };
template <class Res>
struct flatten<Res>:unique<unique_pack<>, Res> { };
int main() {
boost::variant<int, boost::variant<float, int, boost::variant<char, bool>, bool>> vif;
static_assert(std::is_same<flatten<pack<>, decltype(vif)>::type, boost::variant<int, float, char, bool>>::value, "Test");
}

How can a type be removed from a template parameter pack?

I'm searching for a way to remove (let's say for now all occurences of) a type from a template parameter pack. The end result would be a struct that looked like this :
template<typename T, typename...Ts>
struct RemoveT
{
using type = /* a new type out of Ts that does not contain T */
}
Let's say that the marginal case RemoveT<int, int> would be handled by returning void (not handled in the code that follows). My initial design looks like this:
// --------------------------------------------------------------
// 1. A "way" of typedefing variadic number of types ------------
template<typename...Ts>
struct pack {
using type = Ts;
};
// --------------------------------------------------------------
// --------------------------------------------------------------
template<typename T, typename...Ts> struct RemoveT;
template<typename T, typename T1, typename...Ts>
struct RemoveT {
using type = typename pack<T1, typename RemoveT<T, Ts...>::type>::type;
};
template<typename T, typename T1>
struct RemoveT<T, T1> {
using type = T1;
};
template<typename T, typename...Ts>
struct RemoveT<T, T, Ts...> {
using type = typename RemoveT<Ts...>::type;
};
// --------------------------------------------------------------
Now I can't even begin to test this code because the pack structure is not valid C++
Reiteration
Just in case this is helpfull for an answer, some other thoughs on solving it
One could argue that pack is not even useful at all. We could instead move around the RemoveT structure, creating a new RemoveT that only contains the types needed. The problem then transforms in extracting the types out of the struct
We could create type pairs that mimic the behaviour of typelists and take a more recursive approach on this.
Bottom Line
For variadic types Ts and a type T: Can I create Us out of Ts ommiting T ?
The following provides a non-recursive and direct way to remove T from Ts... and, like Jarod42's solutions, yields a std::tuple<Us...> but without the need to use typename ...::type:
#include <tuple>
#include <type_traits>
template<typename...Ts>
using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...));
template<typename T, typename...Ts>
using remove_t = tuple_cat_t<
typename std::conditional<
std::is_same<T, Ts>::value,
std::tuple<>,
std::tuple<Ts>
>::type...
>;
int main()
{
static_assert(std::is_same<
remove_t<int, int, char, int, float, int>,
std::tuple<char, float>
>::value, "Oops");
}
Live example
Following may help:
namespace detail
{
template <typename T, typename Tuple, typename Res = std::tuple<>>
struct removeT_helper;
template<typename T, typename Res>
struct removeT_helper<T, std::tuple<>, Res>
{
using type = Res;
};
template<typename T, typename... Ts, typename... TRes>
struct removeT_helper<T, std::tuple<T, Ts...>, std::tuple<TRes...>> :
removeT_helper<T, std::tuple<Ts...>, std::tuple<TRes...>>
{};
template<typename T, typename T1, typename ...Ts, typename... TRes>
struct removeT_helper<T, std::tuple<T1, Ts...>, std::tuple<TRes...>> :
removeT_helper<T, std::tuple<Ts...>, std::tuple<TRes..., T1>>
{};
}
template <typename T, typename...Ts> struct RemoveT
{
using type = typename detail::removeT_helper<T, std::tuple<Ts...>>::type;
};
static_assert(std::is_same<std::tuple<char, float>,
typename RemoveT<int, int, char, int, float, int>::type>::value, "");
First, move all the specific template names out into a list. There might be a way of specifying a template name, and a list of parameters, giving that template with the parameters, but I haven't been able to figure it out:
template <typename...TArgs> struct TypeList
{
typedef std::tuple<TArgs...> tuple_type;
// whatever other types you need
};
Next, define addition:
template<typename T, typename TList> struct AddT;
template<typename T, typename ... TArgs>
struct AddT< T, TypeList<TArgs...> >
{
typedef TypeList<T, TArgs... > type;
};
Then, define removal:
template<typename R, typename ... TArgs> struct RemoveT;
template<typename R>
struct RemoveT<R>
{
typedef TypeList<> type;
};
template<typename R, typename T, typename ...TArgs>
struct RemoveT<R, T, TArgs...>
{
typedef typename std::conditional
< std::is_same<R, T>::value
, typename RemoveT<R, TArgs...>::type
, typename AddT<T, typename RemoveT<R, TArgs...>::type>::type
>::type type;
};
Finally, test:
int result = 0;
result = std::is_same
< std::tuple<long,double>
, RemoveT<int, int, long, int, double, int>::type::tuple_type
>::value;
assert ( result );

Creating a sub-tuple starting from a std::tuple<some_types...>

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.

Transform tuple to "triangular" tuple

How do I transform this type:
std::tuple<T0, T1, ..., TN1, TN>
into this:
std::tuple<
std::function<T0()>,
std::function<T1(T0)>,
std::function<T2(T0, T1)>,
...
std::function<TN(T0, ..., TN1 )>
>
Right ... isn't suffice, but you could always use pattern matching (i.e. partial specialization) with recursion:
#include <tuple>
#include <functional>
#include <cstdlib>
// A type to store list of integers
template <size_t... ns>
struct integers
{
template <size_t n>
using push_back = integers<ns..., n>;
};
// This generates 'integers<0, 1, 2, ..., n-1>'
template <size_t n>
struct iota
{
typedef typename iota<n-1>::type::template push_back<n-1> type;
};
template <>
struct iota<0>
{
typedef integers<> type;
};
// Put a type to the front of the argument list
template <typename T, typename U>
struct push_front;
template <typename T, typename R, typename... A>
struct push_front<R(A...), T>
{
typedef R type(T, A...);
};
// This converts 'std::tuple<T0, T1, ..., TN>' to the function type
// 'TK(T0, T1, ..., TK-1)' where K is the first parameter
template <size_t, typename...>
struct slice;
template <size_t end, typename First, typename... Rest>
struct slice<end, First, Rest...>
{
typedef typename push_front<typename slice<end-1, Rest...>::type, First>::type type;
};
template <typename First, typename... Rest>
struct slice<0, First, Rest...>
{
typedef First type();
};
// This calls 'slice' on T... for all integers in the list.
template <typename T, typename U>
struct triangularize_impl;
template <typename... T, size_t... n>
struct triangularize_impl<std::tuple<T...>, integers<n...>>
{
typedef std::tuple<std::function<typename slice<n, T...>::type>...> type;
};
// This is a wrapper of 'triangularize_impl'.
template <typename T>
struct triangularize;
template <typename... T>
struct triangularize<std::tuple<T...>>
{
typedef typename triangularize_impl<std::tuple<T...>, typename iota<sizeof...(T)>::type>::type type;
};
As a demo, in g++ 4.7 when we write
triangularize<std::tuple<int, float, double, char>>::type d = 0;
the error message shows
error: conversion from ‘int’ to non-scalar type
‘triangularize<std::tuple<int, float, double, char> >::type {aka
std::tuple<std::function<int()>,
std::function<float(int)>,
std::function<double(int, float)>,
std::function<char(int, float, double)> >}’
requested
Showing the code is correct.