Since I was not able to find such a function (incorrectly?), I'm trying to make a compile-time function (constexpr) function which takes a std::array<T,n> arr and a T t and returns a new std::array<T,n+1> with t added to the end of arr. I've started with something like this:
template <typename T, int n>
constexpr std::array<T,n+1> append(std::array<T,n> a, T t);
template <typename T>
constexpr std::array<T,1> append(std::array<T,0> a, T t)
{
return std::array<T,1>{t};
}
template <typename T>
constexpr std::array<T,2> append(std::array<T,1> a, T t)
{
return std::array<T,2>{a[0], t};
}
Here I get stuck. What I need is a way to expand a in the first n places of the initializer list, and then add t add the end. Is that possible? Or is there another way of doing this?
Of course, it is possible: std::index_sequence<I...> is your friend! You'd simply dispatch to a function which takes a suitable std::index_sequence<I...> as argument and expands the pack with all the values. For example:
template <typename T, std::size_t N, std::size_t... I>
constexpr std::array<T, N + 1>
append_aux(std::array<T, N> a, T t, std::index_sequence<I...>) {
return std::array<T, N + 1>{ a[I]..., t };
}
template <typename T, std::size_t N>
constexpr std::array<T, N + 1> append(std::array<T, N> a, T t) {
return append_aux(a, t, std::make_index_sequence<N>());
}
It was easy to extend Dietmar's answer to a util that lets you constexpr- catenate two arrays:
// constexpr util to catenate two array's.
//
// Usage:
//
// constexpr std::array<int, 2> a1 = { 1, 2 };
// constexpr std::array<int, 2> a2 = { 3, 4 };
//
// constexpr auto a3 = catenate_array(a1, a2);
template <typename T, std::size_t N, std::size_t M, std::size_t... I, std::size_t... J>
constexpr std::array<T, N + M>
catenate_array_aux(std::array<T, N> a1, std::array<T, M> a2, std::index_sequence<I...>, std::index_sequence<J...>) {
return std::array<T, N + M>{ a1[I]..., a2[J]... };
}
template <typename T, std::size_t N, std::size_t M>
constexpr std::array<T, N + M> catenate_array(std::array<T, N> a1, std::array<T, M> a2) {
return catenate_array_aux(a1, a2, std::make_index_sequence<N>(), std::make_index_sequence<M>());
}
Related
I don't think this is possible based on what I've read however I'm hoping someone here may know of some solution that would get this to work.
I have a vector (maths) class for C++
template <typename T, size_t N> class vec;
And want to create a varadic friend function apply to apply a function to these vectors element-wise
i.e.
template <typename F, typename ...Args> friend vec<typename std::result_of<pow(Args&&...)>::type, N> apply(F&& f, const vec<Args, N>&... args);
which is valid (untested yet)
however I want to achieve a pattern like
template <typename F> friend vec<typename std::result_of<F&&(T&&)>::type, N> apply(F&& f, const vec<T, N>& V);
template <typename F> friend vec<typename std::result_of<F&&(T&&, T&&)>::type, N> apply(F&& f, const vec<T, N>& V1, const vec<T, N>& V2);
template <typename F> friend vec<typename std::result_of<F&&(T&&, T&&)>::type, N> apply(F&& f, const vec<T, N>& V1, const T& V2);
template <typename F> friend vec<typename std::result_of<F&&(T&&, T&&)>::type, N> apply(F&& f, const T& V1, const vec<T, N>& V2);
template <typename F, typename U> friend vec<typename std::result_of<F&&(T&&, U&&)>::type, N> apply(F&& f, const vec<T, N>& V1, const vec<U, N>& V2);
template <typename F, typename U> friend vec<typename std::result_of<F&&(T&&, U&&)>::type, N> apply(F&& f, const vec<T, N>& V1, const U& V2);
template <typename F, typename U> friend vec<typename std::result_of<F&&(U&&, T&&)>::type, N> apply(F&& f, const vec<U, N>& V1, const vec<T, N>& V2);
template <typename F, typename U> friend vec<typename std::result_of<F&&(U&&, T&&)>::type, N> apply(F&& f, const U& V1, const vec<T, N>& V2);
note that only one of the arguments is required to be a vector any scalars would be broadcasted to the length of the vector.
The idea is that apply(pow, /*vec<float,N>*/V, /*int*/n) -> {pow(V.v[i],n)...} where i -> 0 ... N rather than apply(pow, /*vec<float,N>*/V, /*int*/n) -> apply(pow, /*vec<float,N>*/V, /*vec<int,N>*/tmp{/*int*/n}) {pow(V.v[i],tmp.v[i])...}
So I would like to be able to write something like the following (which isn't valid C++, but it should give an idea of what I want to achieve)
template <typename F, typename ...Args> friend vec<typename std::result_of<pow(Args&&...)>::type, N> apply(F&& f, const vec<Args, N>&||scalar<Args>::type... args) {
vec<typename std::result_of<pow(Args&&...)>::type, N> r;
for (int i= 0; i < N; i++) { r = f((is_vec<Args>?args.v[i]:args)...); }
return r;
}
EDIT:
Based on Frank's comments I'm looking for something along the lines of
template<typename F, typename ...Args, size_t N>
vec<typename std::enable_if<sum<is_vec<Args,N>...>::value > 0, std::result_of<F&&(base_type<Args>::type&&...)>::type>::type, N>
(F&& f, Args&&...args) {
vec<typename std::result_of<F&&(base_type<Args>::type&&...)>::type, N> result;
for(std::size_t i = 0 ; i < N ; ++i) { result.v[i] = f(extract_v(std::forward<Args>(args),i)...); }
return result;
}
however I'm unsure if this version could even compile as it may be too ambiguous to be able to detriment the value of N.
Not sure to understand what do you exactly want but...
It seems to me that can be useful a custom type traits to extract, from a list of types, the dimension of the Vec, iff (if and only if) in the list of types there is at least one Vec and there aren't Vec's of different lengths.
I suggest something as follows, heavily based on template specialization,
template <std::size_t, typename ...>
struct dimVec;
// ground case for no Vecs: unimplemented for SFINAE failure !
template <>
struct dimVec<0U>;
// ground case with one or more Vecs: size fixed
template <std::size_t N>
struct dimVec<N> : public std::integral_constant<std::size_t, N>
{ };
// first Vec: size detected
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<0U, Vec<T, N>, Ts...> : public dimVec<N, Ts...>
{ };
// another Vec of same size: continue
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<N, Vec<T, N>, Ts...> : public dimVec<N, Ts...>
{ };
// another Vec of different size: unimplemented for SFINAE failure !
template <std::size_t N1, std::size_t N2, typename T, typename ... Ts>
struct dimVec<N1, Vec<T, N2>, Ts...>;
// a not-Vec type: continue
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<N, T, Ts...> : public dimVec<N, Ts...>
{ };
with the help of a template static variable
template <typename ... Args>
static constexpr auto dimVecV { dimVec<0U, Args...>::value };
Now should be easy.
You can write an apply() function that receive a variadic list of args of types Args... and is SFINAE enabled iff dimVecV<Args...> is defined
template <typename F, typename ... Args, std::size_t N = dimVecV<Args...>>
auto apply (F && f, Args ... as)
{ return applyH1(std::make_index_sequence<N>{}, f, as...); }
Observe that the N variable is used to SFINAE enable/disable the function but is useful itself: it's used to pass a std::index_sequence from 0 to N-1 to the first helper function applyH1()
template <std::size_t ... Is, typename F, typename ... Args>
auto applyH1 (std::index_sequence<Is...> const &, F && f, Args ... as)
-> Vec<decltype(applyH2<0U>(f, as...)), sizeof...(Is)>
{ return { applyH2<Is>(f, as...)... }; }
that initialize the returned Vec with single values calculated from the second helper function applyH2()
template <std::size_t I, typename F, typename ... Args>
auto applyH2 (F && f, Args ... as)
{ return f(extrV<I>(as)...); }
that uses a set of template functions extrV()
template <std::size_t I, typename T, std::size_t N>
constexpr auto extrV (Vec<T, N> const & v)
{ return v[I]; }
template <std::size_t I, typename T>
constexpr auto extrV (T const & v)
{ return v; }
to extract the I-th element from a Vec or to pass-through a scalar value.
It's a little long but not particularly complicated.
The following is a full working example
#include <array>
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
class Vec;
template <std::size_t, typename ...>
struct dimVec;
// ground case for no Vecs: unimplemented for SFINAE failure !
template <>
struct dimVec<0U>;
// ground case with one or more Vecs: size fixed
template <std::size_t N>
struct dimVec<N> : public std::integral_constant<std::size_t, N>
{ };
// first Vec: size detected
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<0U, Vec<T, N>, Ts...> : public dimVec<N, Ts...>
{ };
// another Vec of same size: continue
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<N, Vec<T, N>, Ts...> : public dimVec<N, Ts...>
{ };
// another Vec of different size: unimplemented for SFINAE failure !
template <std::size_t N1, std::size_t N2, typename T, typename ... Ts>
struct dimVec<N1, Vec<T, N2>, Ts...>;
// a not-Vec type: continue
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<N, T, Ts...> : public dimVec<N, Ts...>
{ };
template <typename ... Args>
static constexpr auto dimVecV { dimVec<0U, Args...>::value };
template <std::size_t I, typename T, std::size_t N>
constexpr auto extrV (Vec<T, N> const & v)
{ return v[I]; }
template <std::size_t I, typename T>
constexpr auto extrV (T const & v)
{ return v; }
template <typename T, std::size_t N>
class Vec
{
private:
std::array<T, N> d;
public:
template <typename ... Ts>
Vec (Ts ... ts) : d{{ ts... }}
{ }
T & operator[] (int i)
{ return d[i]; }
T const & operator[] (int i) const
{ return d[i]; }
};
template <std::size_t I, typename F, typename ... Args>
auto applyH2 (F && f, Args ... as)
{ return f(extrV<I>(as)...); }
template <std::size_t ... Is, typename F, typename ... Args>
auto applyH1 (std::index_sequence<Is...> const &, F && f, Args ... as)
-> Vec<decltype(applyH2<0U>(f, as...)), sizeof...(Is)>
{ return { applyH2<Is>(f, as...)... }; }
template <typename F, typename ... Args, std::size_t N = dimVecV<Args...>>
auto apply (F && f, Args ... as)
{ return applyH1(std::make_index_sequence<N>{}, f, as...); }
long foo (int a, int b)
{ return a + b + 42; }
int main ()
{
Vec<int, 3U> v3;
Vec<int, 2U> v2;
auto r1 { apply(foo, v2, v2) };
auto r2 { apply(foo, v3, v3) };
auto r3 { apply(foo, v3, 0) };
static_assert( std::is_same<decltype(r1), Vec<long, 2U>>{}, "!" );
static_assert( std::is_same<decltype(r2), Vec<long, 3U>>{}, "!" );
static_assert( std::is_same<decltype(r3), Vec<long, 3U>>{}, "!" );
// apply(foo, v2, v3); // compilation error
// apply(foo, 1, 2); // compilation error
}
You can achieve what you want through a combination of partial template specialization and parameter pack extension.
#include <array>
template<typename T, std::size_t N>
using Vec = std::array<T, N>;
template<typename T>
struct extract {
static auto exec(T const& v, std::size_t) {return v;}
enum { size = 1 };
};
template<typename T, std::size_t N>
struct extract<Vec<T,N>> {
static auto exec(Vec<T,N> const& v, std::size_t i) {return v[i];}
enum {size = N};
};
template<typename T>
auto extract_v(T const& v, std::size_t i) {return extract<T>::exec(v, i);}
template<typename... args>
struct extract_size {
enum {size = 1};
};
template<typename first, typename... rest>
struct extract_size<first, rest...> {
enum {
rest_size_ = extract_size<rest...>::size,
self_size_ = extract<first>::size,
size = rest_size_ > self_size_ ? rest_size_ : self_size_
};
static_assert(self_size_ == 1 || rest_size_ == 1 || rest_size_ == self_size_, "");
};
template<typename F, typename... args_t>
auto apply(F const& cb, args_t&&... args) {
constexpr std::size_t size = extract_size<std::decay_t<args_t>...>::size;
using result_t = decltype(cb(extract_v(std::forward<args_t>(args),0)...));
Vec<result_t, size> result;
for(std::size_t i = 0 ; i < size ; ++i) {
result[i] = cb(extract_v(std::forward<args_t>(args),i)...);
}
return result;
}
I want to be able to do the following:
#include <array>
struct blah { };
template<typename... Args>
constexpr auto foo(Args&&... args)
{
return std::array<blah, sizeof...(Args)>{{ args... }};
}
auto res = foo({}, {});
The following answers aren't satisfying: they just want to check that the parameter pack is of a single type, but I want to convert the values right to it in the arguments (else it does not work).
C++ parameter pack, constrained to have instances of a single type?
Parameter with non-deduced type after parameter pack
Specifying one type for all arguments passed to variadic function or variadic template function w/out using array, vector, structs, etc?
I also can't use initializer_list since I wouldn't be able to count the number of arguments to pass to the array type.
And I especially don't want to type foo(blah{}, blah{});.
What are my possibilities ?
A little bit expanded approach of Jarod42 for lazies (C++17):
#include <utility>
#include <array>
struct blah {};
template <class T, std::size_t I>
using typer = T;
template <class T, std::size_t N, class = std::make_index_sequence<N>>
struct bar_impl;
template <class T, std::size_t N, std::size_t... Is>
struct bar_impl<T, N, std::index_sequence<Is...>> {
static auto foo(typer<T, Is>... ts) {
return std::array<T, N>{{ts...}};
}
};
template <class T = blah, std::size_t N = 10, class = std::make_index_sequence<N>>
struct bar;
template <class T, std::size_t N, std::size_t... Is>
struct bar<T, N, std::index_sequence<Is...>>: bar_impl<T, Is>... {
using bar_impl<T, Is>::foo...;
};
int main() {
bar<>::foo({}, {});
}
[live demo]
Edit:
Some C++14 solution which (as noted by max66) is even simpler than I expected:
#include <utility>
#include <array>
struct blah {};
template <class T, std::size_t I>
using typer = T;
template <class T = blah, std::size_t N = 10, class = std::make_index_sequence<N>>
struct bar;
template <class T, std::size_t N, std::size_t... Is>
struct bar<T, N, std::index_sequence<Is...>>: bar<T, N - 1> {
using bar<T, N - 1>::foo;
static auto foo(typer<T, Is>... ts) {
return std::array<T, N>{{ts...}};
}
};
template <class T>
struct bar<T, 0, std::index_sequence<>> {
static auto foo() {
return std::array<T, 0>{{}};
}
};
int main() {
bar<>::foo({}, {});
}
[live demo]
One more edit:
This one (as suggested by Jarod42) provides exactly the same syntax for invocation as in OP's question:
#include <utility>
#include <array>
struct blah {};
template <class T, std::size_t I>
using typer = T;
template <class T = blah, std::size_t N = 10, class = std::make_index_sequence<N>>
struct bar;
template <class T, std::size_t N, std::size_t... Is>
struct bar<T, N, std::index_sequence<Is...>>: bar<T, N - 1> {
using bar<T, N - 1>::operator();
auto operator()(typer<T, Is>... ts) {
return std::array<T, N>{{ts...}};
}
};
template <class T>
struct bar<T, 0, std::index_sequence<>> {
auto operator()() {
return std::array<T, 0>{{}};
}
};
bar<> foo;
int main() {
foo({}, {});
}
[live demo]
Alright, if you can afford to change the syntax a little bit, this is the best I managed to find:
#include <array>
// to_array implementation taken from
// http://en.cppreference.com/w/cpp/experimental/to_array
namespace detail {
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
to_array_impl(T (&a)[N], std::index_sequence<I...>)
{
return { {a[I]...} };
}
}
template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
{
return detail::to_array_impl(a, std::make_index_sequence<N>{});
}
// End of to_array implementation
struct blah { };
template<std::size_t N>
constexpr auto foo(const blah(&arr)[N])
{
return to_array(arr);
}
int main()
{
auto res = foo({{}, {}});
return 0;
}
As you can see, foo({}, {}) became foo({{}, {}}).
Here is a working example: https://ideone.com/slbKi3
The issue with the way you want it (foo({}, {})) is that the compiler has no way to know what it is supposed to convert {} to.
I tried to find a way to let it know but it didn't listen at all.
If you accept, as proposed by Telokis, to add a bracket level calling foo()
auto res = foo( { {}, {} } );
you can use the C-style array trick proposed by Telokis and a simple cycle to initialize the returned value
template <std::size_t N>
constexpr std::array<blah, N> foo (const blah(&arr)[N])
{
std::array<blah, N> ret;
for ( auto i = 0U ; i < N ; ++i )
ret[i] = arr[i];
return ret;
}
Unfortunately the operator[] for std::array is constexpr only starting from C++17, so the preceding foo is effectively constexpr only starting from C++17.
So you can call
auto res = foo( { {}, {} } );
also in C++11 and C++14, but
constexpr auto res = foo( { {}, {} } );
only starting from C++17.
One (limited) ways to keep your syntax is to have several overloads:
constexpr auto foo(const blah& a1)
{
return std::array<blah, 1>{{ a1 }};
}
constexpr auto foo(const blah& a1, const blah& a2)
{
return std::array<blah, 2>{{ a1, a2 }};
}
// ...
// Up to N
constexpr auto foo(const blah& a1, const blah& a2, .., const blah& aN)
{
return std::array<blah, N>{{ a1, a2, .., aN }};
}
W.F. in his answer shows a way to generate it thanks to variadic at class scope.
In C++17 you can use a combination of static_assert and std::conjunction like this:
#include <array>
#include <type_traits>
struct blah {};
template <typename Arg, typename... Args>
constexpr auto foo_helper(Arg&& first, Args&&... rest) {
static_assert(std::conjunction_v<std::is_same<Arg, Args>...>);
return std::array<blah, 1 + sizeof...(Args)>{first, rest...};
}
template <typename... Args>
constexpr auto foo(Args&&... args) {
return foo_helper(std::forward<Args>(args)...);
}
auto res = foo(blah{}, blah{})
I want to build a template function to convert std::array to a general point which has a constructor accepting its coordinate arguments.
template<typename PointT, size_t N>
PointT to(std::array<double, N> const& a)
{
return PointT(a[0], a[1], ...); // How to expand a?
}
My question is: is there a way to expand the array a?
template <typename PointT, std::size_t N, std::size_t... Is>
PointT to(std::array<double, N> const& a, std::index_sequence<Is...>)
{
return PointT(a[Is]...);
}
template <typename PointT, std::size_t N>
PointT to(std::array<double, N> const& a)
{
return to<PointT>(a, std::make_index_sequence<N>{});
}
DEMO
Note: index_sequence/integer_sequence utilities are available starting from C++14. Since the question is tagged as C++11, the demo code from this answer exploits the following implementation:
namespace std
{
template <std::size_t... Is>
struct index_sequence {};
template <std::size_t N, std::size_t... Is>
struct make_index_sequence_h : make_index_sequence_h<N - 1, N - 1, Is...> {};
template <std::size_t... Is>
struct make_index_sequence_h<0, Is...>
{
using type = index_sequence<Is...>;
};
template <std::size_t N>
using make_index_sequence = typename make_index_sequence_h<N>::type;
}
Given two constexpr arrays (type[N] or std::array<type, N>)
constexpr int A[5] { 0, 1, 2, 3, 4 };
constexpr int B[5] { 5, 4, 3, 2, 1 };
is it possible to initialize a new constexpr array performing an element-wise operation (or constexpr function)?
For example, can this code
constexpr int sum(int i) { return A[i] + B[i]; }
constexpr int S[5] { sum(0), sum(1), sum(2), sum(3), sum(4) };
be rewritten more conveniently in a form that calls sum(i) for every element in S?
Similar things have been done many times already, but here's a solution for this particular compile-time operation on arrays ;)
template<int... Is>
struct seq {};
template<int I, int... Is>
struct gen_seq : gen_seq<I-1, I-1, Is...> {};
template<int... Is>
struct gen_seq<0, Is...> : seq<Is...> {};
#include <array>
template<class T, int N, int... Is>
constexpr std::array<T, N> sum(T const (&lhs)[N], T const (&rhs)[N], seq<Is...>)
{
return {{lhs[Is]+rhs[Is]...}};
}
template<class T, int N>
constexpr auto sum(T const (&lhs)[N], T const (&rhs)[N])
-> decltype( sum(lhs, rhs, gen_seq<N>{}) )
{
return sum(lhs, rhs, gen_seq<N>{});
}
#include <iostream>
int main()
{
constexpr int a[] = {1,2,3,4,5};
constexpr int b[] = {1,2,3,4,5};
constexpr auto c = sum(a,b);
for(auto e : c) std::cout << e << ", ";
}
N.B. std::array::operator[] is not constexpr in C++11, therefore I've used raw arrays as input.
For arbitrary binary functions:
template<class T, int N, class F, int... Is>
constexpr auto transform(T const (&lhs)[N], T const (&rhs)[N], F f,
seq<Is...>)
-> std::array<decltype( f(lhs[0], rhs[0]) ), N>
{
return {{ f(lhs[Is], rhs[Is])... }};
}
template<class T, int N, class F>
constexpr auto transform(T const (&lhs)[N], T const (&rhs)[N], F f)
-> decltype( transform(lhs, rhs, f, gen_seq<N>{}) )
{
return transform(lhs, rhs, f, gen_seq<N>{});
}
constexpr int sum(int l, int r) { return l+r; }
// ...
constexpr auto c = transform(a,b,sum);
For arbitrary n-ary functions and arbitrary array-like types:
template<class F, class... Args>
constexpr auto index_invoke(F f, int i, Args&&... args)
-> decltype( f(args[i]...) )
{
return f(args[i]...);
}
template<class F, int... Is, class... Args>
constexpr auto transform_impl(F f, seq<Is...>, Args&&... args)
-> std::array<decltype( f(args[0]...) ), sizeof...(Is)>
{
return {{ index_invoke(f, Is, std::forward<Args>(args)...)... }};
}
template <class T, class...>
struct get_extent_helper
: std::integral_constant<int,
std::extent<typename std::remove_reference<T>::type>{}>
{};
template<class F, class... Args>
constexpr auto transform(F f, Args&&... args)
-> decltype( transform_impl(f, gen_seq< get_extent_helper<Args...>{} >{},
std::forward<Args>(args)...) )
{
using N = get_extent_helper<Args...>;
return transform_impl(f, gen_seq<N{}>{}, std::forward<Args>(args)...);
}
More lightweight with an alias-template:
template <class T, class...>
using get_extent_helper =
std::integral_constant<int,
std::extent<typename std::remove_reference<T>::type>{}>;
But this is buggy under g++4.8.1
How can I split an argument pack in two equal parts?
For example, I would like to do something like this:
template<typename T> T sum(const T& t)
{ return t; }
template<typename T> T sum(const T& t1, const T& t2)
{ return t1 + t2; }
template<typename ...T> T sum(T&& ...t)
{ sum(first_half(t)...) + sum(second_half(t)...); }
I would suggest something along the lines of this, as the required nesting depth and amount of boilerplate code is lower than in the suggested solution. However, the actual parameter pack is never split, instead two ranges of indices are produced to index the input values which are forwarded as tuples to be then accessed via std::get. Aside from the nesting depth, it is far easier to specify how the splitting is performed (rounding up, down, or taking a power of two and the remainder).
int sum(int a) { return a; }
int sum(int a, int b) { return a + b; }
template<typename... Args> int sum(Args&&... args);
template<typename Tuple, size_t... index>
int sum_helper(pack_indices<index...>, Tuple&& args)
{
return sum(std::get<index>(args)...);
}
template <size_t begin, size_t end, typename... Args>
int sum_helper(Args&&... args)
{
typename make_pack_indices<end, begin>::type indices;
return sum_helper(indices, std::forward_as_tuple(std::forward<Args>(args)...));
}
template<typename... Args>
int sum(Args&&... args)
{
constexpr size_t N = sizeof...(Args);
return sum(
sum_helper<0, N/2>(std::forward<Args>(args)...),
sum_helper<N/2, N>(std::forward<Args>(args)...)
);
}
which requires
template <size_t...>
struct pack_indices {};
template <size_t Sp, typename IntPack, size_t Ep>
struct make_indices_imp;
template <size_t Sp, size_t Ep, size_t... Indices>
struct make_indices_imp<Sp, pack_indices<Indices...>, Ep>
{
typedef typename make_indices_imp<Sp+1, pack_indices<Indices..., Sp>, Ep>::type type;
};
template <size_t Ep, size_t... Indices>
struct make_indices_imp<Ep, pack_indices<Indices...>, Ep>
{
typedef pack_indices<Indices...> type;
};
template <size_t Ep, size_t Sp = 0>
struct make_pack_indices
{
static_assert(Sp <= Ep, "make_tuple_indices input error");
typedef typename make_indices_imp<Sp, pack_indices<>, Ep>::type type;
};
A possible solution is to convert the argument list into a tuple and then extract the needed arguments via std::get and std::index_sequence (it will appear only in C++14, but you can easily implement the same functionality in the meantime).
Untested example code follows:
template<class T1, class T2>
struct append_index_seq;
template<std::size_t N, std::size_t... NN>
struct append_index_seq<N, std::index_sequence<NN...>> {
using type = std::index_sequence<N, NN...>;
};
template<std::size_t M, std::size_t N1, std::size_t... N>
struct add_index_seq_impl {
using type = append_index_seq<N1+M, add_index_seq<N, M>::type>::type;
};
template<std::size_t M, std::size_t N1>
struct add_index_seq_impl {
using type = std::index_sequence<N1+M>::type;
};
template<std::size_t M, std::size_t... N>
struct add_index_seq;
template<std::size_t M, std::size_t... N>
struct add_index_seq<m, std::index_sequence<N...>> {
using type = add_index_seq_impl<M, N...>;
}
template<std::size_t N>
struct get_first_half {
static_assert(N % 2 == 0, "N must be even");
using indexes = std::make_index_sequence<N/2>;
};
template<std::size_t N>
struct get_second_half {
static_assert(N % 2 == 0, "N must be even");
using indexes_1st = std::make_index_sequence<N/2>;
using indexes = add_index_seq<N/2, indexes_1st>::type;
};
template<class F, class Tuple, std::size_t... I>
auto apply(F&& f, Tuple&& t, index_sequence<I...>)
{
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template<class ...T> T sum(T&& ...t)
{
auto params = std::make_tuple(t);
T r1 = apply(sum, params, get_first_half<T...>::indexes);
T r2 = apply(sum, params, get_second_half<T...>::indexes);
return r1 + r2;
}