Expand two parameter packs - c++

Consider following piece of code:
static constexpr size_t Num {2};
struct S {
std::array<size_t, Num> get () { return {1, 2}; }
};
struct S1 : S {};
struct S2 : S {};
struct M {
template <typename T>
typename std::enable_if<std::is_same<T, S1>::value, S1>::type get () const {
return S1 {};
}
template <typename T>
typename std::enable_if<std::is_same<T, S2>::value, S2>::type get () const {
return S2 {};
}
};
I want to have a function which merges two or more std::arrays making one std::array.
So far I ended with something like this:
template <typename Mode, typename... Rs, size_t... Ns>
std::array<size_t, sizeof... (Rs)*Num> get_array (const Mode& mode, Sequence::Sequence<Ns...>) {
return {std::get<Ns> (mode.template get<Rs...> ().get ())...};
}
I want to have that the following code
M m;
auto x = get_array<M, S1, S2> (m, Sequence::Make<2> {});
produces std::array<size_t, 4> filled with {1, 2, 1, 2}.
Where Sequence::Sequence and Sequence::Make are described here.
I know that placing ... of Rs is incorrect in this context (If sizeof... (Rs) is 1 then it is fine, std::array<size_t, 2> with {1, 2} is returned) but I have no idea where to put it to make expansion which looks like this:
std::get<0> (mode.template get<Rs[0]> ().get ()),
std::get<1> (mode.template get<Rs[0]> ().get ()),
std::get<0> (mode.template get<Rs[1]> ().get ()),
std::get<1> (mode.template get<Rs[1]> ().get ());
Of course Rs[0] I mean first type from parameter pack.
Is it even possible?

Assuming that we're using Xeo's index sequence implementation, we can do something like this:
First create a function for concatenating two arrays. It receives the arrays, plus an index sequence for each one (detail::seq is the index_sequence type)
template<class T, size_t N, size_t M, size_t... I, size_t... J>
std::array<T, N + M> concat(const std::array<T, N>& arr1, const std::array<T, M>& arr2, detail::seq<I...>, detail::seq<J...>)
{
return {arr1[I]..., arr2[J]...};
}
Next, call this function from your get_array function, except we're going to double the seq that we received from the call in main:
template<class MODE, class... T, size_t... I>
auto get_array(MODE m, detail::seq<I...>) ->decltype(concat(m.template get<T>().get()..., detail::seq<I...>{}, detail::seq<I...>{})){
return concat(m.template get<T>().get()..., detail::seq<I...>{}, detail::seq<I...>{});
}
The call in main looks just like it did in your code:
M m;
auto x = get_array<M, S1, S2>(m, detail::gen_seq<2>{});
Where detail::gen_seq is the implementation of make_index_sequence that Xeo had.
Live Demo
Note that I replaced unsigned with size_t in Xeo's index sequence impl.
In C++14 we don't need to implement seq or gen_seq, and we also wouldn't need a trailing -> decltype() after our function.
In C++17 it would be even easier to generalize our concatenation for an arbitrary number of arrays, using fold expressions.

Yes, this can be done, with the standard index_sequence tricks:
template <class T, std::size_t N1, std::size_t N2, std::size_t ... Is, std::size_t ... Js>
std::array<T, N1 + N2> merge_impl(const std::array<T, N1>& a1,
const std::array<T, N2>& a2,
std::index_sequence<Is...>,
std::index_sequence<Js...>) {
return {a1[Is]..., a2[Js]...};
}
template <class T, std::size_t N1, std::size_t N2>
std::array<T, N1 + N2> merge(const std::array<T, N1>& a1, const std::array<T, N2>& a2) {
return merge_impl(a1, a2,
std::make_index_sequence<N1>{},
std::make_index_sequence<N2>{});
}
index_sequence is only in the 14 standard, but can be easily implemented in 11; there are many resources (including on SO) that describe how to do so (edit: it's basically equivalent to your Sequence stuff, may as well get used to the standard names for them). Live example: http://coliru.stacked-crooked.com/a/54dce4a695357359.

To start with, this is basically asking to concatenate an arbitrary number of arrays. Which is very similar to concatenate an arbitrary number of tuples, for which there is a standard library function, even in C++11: std::tuple_cat(). That gets us almost there:
template <class... Ts, class M>
auto get_array(M m) -> decltype(std::tuple_cat(m.template get<Ts>()...)) {
return std::tuple_cat(m.template get<Ts>()...);
}
Note that I flipped the template parameters, so this is just get_array<T1, T2>(m) instead of having to write get_array<M, T1, T2>(m).
Now the question is, how do we write array_cat? We'll just use tuple_cat and convert the resulting tuple to an array. Assume an implementation of index_sequence is available (which is something you'll want in your collection anyway):
template <class T, class... Ts, size_t... Is>
std::array<T, sizeof...(Ts)+1> to_array_impl(std::tuple<T, Ts...>&& tup,
std::index_sequence<Is...> ) {
return {{std::get<Is>(std::move(tup))...}};
}
template <class T, class... Ts>
std::array<T, sizeof...(Ts)+1> to_array(std::tuple<T, Ts...>&& tup) {
return to_array_impl(std::move(tup), std::index_sequence_for<T, Ts...>());
}
template <class... Tuples>
auto array_cat(Tuples&&... tuples) -> decltype(to_array(std::tuple_cat(std::forward<Tuples>(tuples)...))) {
return to_array(std::tuple_cat(std::forward<Tuples>(tuples)...));
}
And that gives you:
template <class... Ts, class M>
auto get_array(M m) -> decltype(array_cat(m.template get<Ts>()...)) {
return array_cat(m.template get<Ts>()...);
}
which handles arbitrarily many types.

So here's for an arbitrary number of same-type arrays. We are basically implementing a highly restrictive version of tuple_cat, made substantially easier because the number of elements in the arrays is the same. I make use of a couple C++14 and 17 library features that are all readily implementable in C++11.
template<class, size_t> struct div_sequence;
template<size_t...Is, size_t Divisor>
struct div_sequence<std::index_sequence<Is...>, Divisor>
{
using quot = std::index_sequence<Is / Divisor...>;
using rem = std::index_sequence<Is % Divisor...>;
};
template<class T, size_t...Ns, size_t...Is, class ToA>
std::array<T, sizeof...(Ns)> array_cat_impl(std::index_sequence<Ns...>,
std::index_sequence<Is...>,
ToA&& t)
{
// NB: get gives you perfect forwarding; [] doesn't.
return {std::get<Is>(std::get<Ns>(std::forward<ToA>(t)))... };
}
template<class Array, class... Arrays,
class VT = typename std::decay_t<Array>::value_type,
size_t S = std::tuple_size<std::decay_t<Array>>::value,
size_t N = S * (1 + sizeof...(Arrays))>
std::array<VT, N> array_cat(Array&& a1, Arrays&&... as)
{
static_assert(std::conjunction_v<std::is_same<std::decay_t<Array>,
std::decay_t<Arrays>>...
>, "Array type mismatch");
using ind_seq = typename div_sequence<std::make_index_sequence<N>, S>::rem;
using arr_seq = typename div_sequence<std::make_index_sequence<N>, S>::quot;
return array_cat_impl<VT>(arr_seq(), ind_seq(),
std::forward_as_tuple(std::forward<Array>(a1),
std::forward<Arrays>(as)...)
);
}
We can also reuse the tuple_cat machinery, as in #Barry's answer. To sidestep potential QoI issues, avoid depending on extensions and also extra moves, we don't want to tuple_cat std::arrays directly. Instead, we transform the array into a tuple of references first.
template<class TupleLike, size_t... Is>
auto as_tuple_ref(TupleLike&& t, std::index_sequence<Is...>)
-> decltype(std::forward_as_tuple(std::get<Is>(std::forward<TupleLike>(t))...))
{
return std::forward_as_tuple(std::get<Is>(std::forward<TupleLike>(t))...);
}
template<class TupleLike,
size_t S = std::tuple_size<std::decay_t<TupleLike>>::value >
auto as_tuple_ref(TupleLike&& t)
-> decltype(as_tuple_ref(std::forward<TupleLike>(t), std::make_index_sequence<S>()))
{
return as_tuple_ref(std::forward<TupleLike>(t), std::make_index_sequence<S>());
}
We can then transform the tuple_cat'd references back into an array:
template <class R1, class...Rs, size_t... Is>
std::array<std::decay_t<R1>, sizeof...(Is)>
to_array(std::tuple<R1, Rs...> t, std::index_sequence<Is...>)
{
return { std::get<Is>(std::move(t))... };
}
template <class R1, class...Rs>
std::array<std::decay_t<R1>, sizeof...(Rs) + 1> to_array(std::tuple<R1, Rs...> t)
{
static_assert(std::conjunction_v<std::is_same<std::decay_t<R1>, std::decay_t<Rs>>...>,
"Array element type mismatch");
return to_array(t, std::make_index_sequence<sizeof...(Rs) + 1>());
}
Finally, array_cat itself is just
template <class... Arrays>
auto array_cat(Arrays&&... arrays)
-> decltype(to_array(std::tuple_cat(as_tuple_ref(std::forward<Arrays>(arrays))...)))
{
return to_array(std::tuple_cat(as_tuple_ref(std::forward<Arrays>(arrays))...));
}
Any decent optimizer should have little difficulty optimizing the intermediate tuples of references away.

Related

Making an index sequence tuple

Is there a way to create index tuple with compile-time known size like
std::tuple<int, int, ...> tup = make_index_tuple(100); // -> tup == (0, 1, 2, ..., 99)
Maybe somehow using std::make_index_sequence?
There is a kind of similar question about uninitialized tuple type but with structures involved
EDIT
I am trying to test my hand-written string formatting function with a signature like this
template<class... Args>
std::string format(std::string_view fmt, const Args&... args)
so I implemented a test, that requires to pass a sequence of ints 0, 1, 2, 3, ..., 99 to args. If there is a way to create tuple like so, then I could use std::apply to pass required arguments. If there are other ways i'd be glad to hear them too :)
pass a sequence of ints 0, 1, 2, 3, ..., 99 to [function arguments]
You don't need tuples. Do this:
template <std::size_t ...I>
void foo(std::index_sequence<I...>)
{
format("foo", I...);
}
int main()
{
foo(std::make_index_sequence<42>());
}
If you insist on std::apply, it understands std::array out of the box. You just need to handle the first parameter separately, since it's not an int.
const int n = 32;
std::array<int, n> array;
for (int i = 0; i < n; i++)
array[i] = i;
std::apply([](auto ...params){format("foo", params...);}, array);
For educational purposes, here's the answer to the original question. This is how you make a tuple:
template <typename T, typename I>
struct n_tuple_helper {};
template <typename T, std::size_t ...I>
struct n_tuple_helper<T, std::index_sequence<I...>>
{
using type = std::tuple<std::enable_if_t<I || true, T>...>;
};
template <typename T, std::size_t N>
using n_tuple = typename n_tuple_helper<T, std::make_index_sequence<N>>::type;
Now, n_tuple<int, 3> expands to std::tuple<int, int, int>
Above have mentioned how you could accomplish your idea by creating std::array. In case you still want to see how you should create a tuple:
template<typename T, T ...I>
auto make_tuple_sequence_helper(std::integer_sequence<T, I...>)
{
return std::make_tuple(I...);
}
template<std::size_t I, typename T>
auto make_tuple_sequence()
{
return make_tuple_sequence_helper(std::make_integer_sequence<T, I>());
}
Then you call it in main:
auto int_tuple = make_tuple_sequence<5, int>();
// Equivalent to `std::make_tuple(0,1,2,3,4)`
auto long_tuple = make_tuple_sequence<5, long>();
// Equivalent to `std::make_tuple(0l,1l,2l,3l,4l)`
auto size_t_tuple = make_tuple_sequence<5, std::size_t>();
// Equivalent to `std::make_tuple(0z,1z,2z,3z,4z)`
Note that you could also remove the typename T, if you know you only want tuple<int...> :
template<int ...I>
auto make_tuple_sequence_helper(std::integer_sequence<int, I...>)
{
return std::make_tuple(I...);
}
template<std::size_t I,>
auto make_tuple_sequence()
{
return make_tuple_sequence_helper(std::make_integer_sequence<int, I>());
}
And in main would be:
auto int_tuple = make_tuple_sequence<5>();
While the accepted answer should work for you too, I think it can still be improved. Since your goal appears to be calling the format function with an array of arguments, we will try solving this issue directly.
// declaration of format
template <typename ...Args>
std::string format(std::string_view fmt, const Args &...args);
// variadic template which uses type deduction to obtain the indices as template parameters
template <typename T, std::size_t ...I>
std::string format_arr_impl(std::string_view fmt,
T arr[sizeof...(I)],
std::index_sequence<I...>)
{
return format(fmt, arr[I]...);
}
// wrapper function, so that we don't have to call `std::make_index_sequence` each time
// this accepts a builtin array, but we can also add an overload for std::array
template <typename T, std::size_t N>
std::string format_arr(std::string_view fmt, T (&arr)[N])
{
return format_arr_impl(fmt, arr, std::make_index_sequence<N>());
}
// we can now call format for an array very easily
int main()
{
int data[] {11, 22, 33};
format_arr("{} {} {}", data);
}
Or alternatively, if you really insist on creating a tuple, we can also do the following:
// make use of the same index_sequence trick to deduce the indices
template <typename T, std::size_t ...I>
auto tuple_from_arr_impl(T arr[sizeof...(I)], std::index_sequence<I...>)
{
return std::make_tuple(arr[I]...);
}
// once again, we could also use a std::array instead of a reference to a builtin array
template <typename T, std::size_t N>
auto tuple_from_arr(std::string_view fmt, T (&arr)[N])
{
return tuple_from_arr_impl(fmt, arr, std::make_index_sequence<N>());
}
With the latter approach, we obtain a tuple where each member is an element of the array. We could then use std::apply to print the members.

Unrolling and forwarding arrays

I'm having trouble unrolling and forwarding a parameter pack of std::arrays to another function
Suppose we have a function that takes a single std::array and I want to unroll it and pass it as an argument to some other function I can do so by doing this:
template<typename T, typename...Ts>
void other_function(T, Ts...) { /* Do stuff with Ts */ }
template<typename T, size_t Size, size_t... I>
void forward_array(std::array<T, Size>& array_arg, std::index_sequence<I...>)
{
other_function(array_arg[I]...);
// for Size == 3 let's say we get the same thing as we would write
// other_function(array_arg[0], array_arg[1], array_arg[2]
// I skipped the std::forward
}
Now let's say we have a function that does this same thing, but it takes multiple arrays that can be of different size.
template<typename T, size_t... Sizes /*, size_t... I_Sequence0, size_t... I_Sequence1, ... I_SequenceN */>
void forward_many_arrays(std::array<T, Sizes>&... array_args /*, ???*/)
{
other_func( /* ??? */);
}
I want to unfold each array_arg and pass it to other_func, but how do I do that exactly here?. We would need a way to index into each array arg.
In my actual program, I have a class that has a member std::array of std::reference_wrapper which is not default constructable and I'm trying to provide an alternative constructor for that class that takes any number of arrays&, where the sum of their sizes matches the member array size and delegate it to the explicit constructor that takes T references, but I'm kind of stuck cause I don't know how to handle the unrolling.
You might have a "generic" getter
template <std::size_t I, typename Container, typename ... Containers>
decltype(auto) get(Container&& container, Containers&&...containers)
{
constexpr std::size_t size = std::tuple_size_v<std::decay_t<Container>>;
if constexpr (I < size) {
return container[I];
} else {
return get<I - size>(containers...);
}
}
Used like:
template <typename...Ts>
void other_function(Ts... ts) { ((std::cout << ts << " "), ...); }
template<typename... Ts, size_t... Is>
void forward_many_arrays(std::index_sequence<Is...>, Ts&&...ts)
{
other_function(get<Is>(ts...)...);
}
template<typename... Ts>
void forward_many_arrays(Ts&&...ts)
{
forward_many_arrays(std::make_index_sequence<(std::tuple_size_v<std::decay_t<Ts>> + ...)>(), ts...);
}
Demo
An implementation based on simple recursion:
template<std::size_t n, class Fn, class T, class... Ts>
void apply_all_impl(Fn fn, T& t, Ts&... ts) {
if constexpr (n == 0)
fn(t, ts...);
else
std::apply([&](auto&... args) {
apply_all_impl<n - 1>(fn, ts..., args...);
}, t);
}
template<class Fn, class... Ts>
void apply_all(Fn fn, Ts&... ts) {
apply_all_impl<sizeof...(Ts)>(fn, ts...);
}
Usage example:
std::array<int, 3> arr1{1, 2, 3};
std::array<int, 4> arr2{4, 5, 6, 7};
auto print_all = [](auto... ts) { (std::cout << ... << ts); };
apply_all(print_all, arr1, arr2); // Output: 1234567
Demo

c++ variadic template argument iterating

I'm pretty inexperienced in such things, but I'm trying to create a template function that evaluates a n-variable function at "rotated" argument (see example below) and returns a vector of all these values.
For example for n=3 with a function f(x,y,z) the returned triple\vector should be
< f(x,0,0), f(0,x,0), f(0,0,x) >
The naive version of what I need could look like the following (not necessary correct\working)
typedef FunctionSignature Function;
template<class Function, size_t Dimensions>
std::array<Function::Out,Dimensions> F(Function::InComponent x)
{
std::array<Function::Out,Dimensions> Result;
for (i=0; i<Dimensions; i++)
Result[i] = Function::f("rotate((x,0,...,0),i)");
return Result;
}
But how to make the rotate thing.
I also hope that the run-time for could be somehow be eliminated since n is well known in time of compilation.
template<class Function, size_t... Is, size_t... Js>
typename Function::Out call_f(typename Function::InComponent x,
std::index_sequence<Is...>,
std::index_sequence<Js...>) {
return Function::f((void(Is), 0)..., x, (void(Js), 0)...);
}
template<class Function, size_t Dimensions, size_t... Is>
std::array<typename Function::Out, Dimensions> F(typename Function::InComponent x,
std::index_sequence<Is...>)
{
return {{ call_f<Function>(x, std::make_index_sequence<Is>(),
std::make_index_sequence<Dimensions - Is - 1>())... }};
}
template<class Function, size_t Dimensions>
std::array<typename Function::Out,Dimensions> F(typename Function::InComponent x)
{
return F<Function, Dimensions>(x, std::make_index_sequence<Dimensions>());
}
For C++11, search on SO for an implementation of make_index_sequence.
Demo.

Spliting a std::array into a tuple of smaller sized std::array

I'm trying to split a std::array<T, N> into a tuple of smaller arrays, like std::tuple<std::array<T, N1>, std::array<T, N2>, ...> where N1 + N2 + ... = N.
namespace detail {
// Summation of the given values
template <class T>
constexpr T sum(const T& x) { return x; }
template <class T, class ...Args>
constexpr auto sum(const T& x, Args&&... args)
{ return x + sum(std::forward<Args>(args)...); }
}
template <class T, std::size_t... Ns>
constexpr
std::tuple<std::array<T, Ns>...>
f(const std::array<T, detail::sum(Ns...)>& x)
{
// How do I implement this function?
}
int main()
{
constexpr std::array<Foo, 5> arr = { ... };
constexpr auto t = f<Foo, 2,3>(arr);
}
Actually I already implemented f but it's based on a loop which simply creates an empty array and copies the elements of the given array, but it doesn't work if T is not default_constructible.
I tried to utilize std::integer_sequence and std::make_index_sequence, but I think i'm totally lost with no clue.
Can anyone help me implement the function please?
Write
template<class T,size_t...Is,size_t N>
std::array<T,sizeof...(Is)>
extract(std::array<T,N>const&,std::index_sequence<Is...>){
return {{arr[Is]...}};
}
now we just need to turn {1,2,3} into {{0},{1,2},{3,4,5}} roughly, with everything being C++ index sequences (so syntax).
Map {3,4,0} to {0,1,2} -- a count of indexes to subarrays. Then map {3,4,0} x 1 to {3,4,5,6} and similar for the others. That gives us the indexes inside the subarrays, which we feed to extract and bob is your uncle.
template<size_t n, size_t...counts>
constexpr auto
foo( std::index_sequence<counts...> )
-> offset_seq<
sum_n<n>(counts...),
std::make_index_sequence<get_n<n,counts...> >
>{ return {}; }
with various helpers to be written is the {3,4,0} x 1 to {3,4,5,6} portion, for example.

constexpr function to add an integer to an array

I am trying to implement a constexpr function "add42" that would allow me to do:
constexpr array<int,5> arr = {1,2,3,4,5};
constexpr array<int,5> arr2 = add42(0,arr); //I want arr2=={43,2,3,4,5}
That is, add an integer at a given index to an array statically (with constexpr).
Since my array "arr" is immutable, I have to actually create a new one from "arr" and my index. That is why I coded this function:
template<int DIM, typename... ARGS> auto constexpr
add42(int index, array<int,DIM> intergerArray, ARGS... unpackedIntegers) -> array<int,DIM> {
return
( sizeof...(ARGS)==DIM ) ?
array<int,DIM>( {{unpackedIntegers...}} ) :
( (sizeof...(ARGS)-1)==index ) ?
add42(index, intergerArray, unpackedIntegers..., intergerArray[sizeof...(ARGS)-1]+42 ) :
add42(index, intergerArray, unpackedIntegers..., intergerArray[sizeof...(ARGS)-1] ) ;
}
That is, all the integers of my array are recursively unpacked from the array, added 42 if at the right index, and appened at the end of the ARGS list. When this arg list contains all the integers from the array, we are done so we can repack into a new array.
However I get this error (gcc 4.7.2)
error: no matching function for call to 'add42(int, const std::array<int, 5u>&)'|
note: candidate is:|
template<int DIM, class ... ARGS> constexpr std::array<int, DIM> add42(int, std::array<int, DIM>, ARGS ...)|
note: template argument deduction/substitution failed:|
note: mismatched types 'int' and '#'integer_cst' not supported by dump_type#<type error>'|
Can you explain me what is the problem and how to correct it ?
This question seems similar to C++11: Compile Time Calculation of Array but is not (At least, I am unable to figure out how to use it deirectly): here, I want to create an new array from an already existent one, not from a known sequence of integers.
EDIT
Now I get infinite instantiation, even when no recursion called. Here is a simplified example :
template<size_t DIM, typename... ARGS> auto constexpr
add42(int index, array<int,DIM> integerArray, ARGS... unpackedIntegers) -> array<int,DIM> {
return
( true ) ?
array<int,DIM>( {{unpackedIntegers...}} ) :
add42(index, integerArray, unpackedIntegers..., integerArray[(sizeof...(ARGS)-1)] ) ;
}
Why does my compiler try to compile the last function call ?
EDIT 2
Apparently, I have to provide 2 function in order not to confuse the compiler:
template<size_t DIM, class... ARGS> constexpr auto
add42(int index, array<int,DIM> integerArray, ARGS... unpackedIntegers) -> typename enable_if<sizeof...(ARGS)==DIM ,array<int,DIM>>::type
{
return array<int,DIM>( {{unpackedIntegers...}} );
}
template<size_t DIM, class... ARGS> constexpr auto
add42(int index, array<int,DIM> integerArray, ARGS... unpackedIntegers) -> typename enable_if<sizeof...(ARGS)!=DIM ,array<int,DIM>>::type
{
return
( sizeof...(ARGS) == index ) ?
add42(index, integerArray, unpackedIntegers..., integerArray[sizeof...(ARGS)]+42) :
add42(index, integerArray, unpackedIntegers..., integerArray[sizeof...(ARGS)]) ;
}
But it still does not work:
recursively required from [[name of the second function]]
Apparently, a variadic function cannot call "recursively" one of its overloads.
Am I right ? What workaround is possible ?
You should use
template<size_t DIM, typename... ARGS> auto constexpr
add42(int index, array<int,DIM> intergerArray, ARGS... unpackedIntegers)
since array's second parameter has type size_t, not int.
Unfortunately, std::array::operator[] is not constexpr.
Compiler options: just plain -std=c++11
gcc <= 4.6: -std=c++0x and replace the using directive with a typedef
#include <cstddef>
//#include <array>
#include <type_traits>
#include <iostream>
template < typename T, std::size_t dim >
struct c_array
{
T arr[dim];
constexpr T operator[](std::size_t index)
{ return arr[index]; }
T const* begin() const
{ return arr; }
T const* end() const
{ return arr+dim; }
};
// I like the overloaded version better (instead of enable_if) :)
template < typename T, std::size_t dim, typename... TT >
constexpr c_array<T, dim>
add_to(T s, c_array<T, dim> in, std::size_t index, std::true_type, TT... pp)
{
return {{pp...}};
}
template < typename T, std::size_t dim, typename... TT >
constexpr c_array<T, dim>
add_to(T s, c_array<T, dim> in, std::size_t index, std::false_type, TT... pp)
{
using test = std::integral_constant<bool, (sizeof...(pp)+1 == dim)>;
return index == sizeof...(pp)
? add_to(s, in, index, test{}, pp..., in[sizeof...(pp)]+s)
: add_to(s, in, index, test{}, pp..., in[sizeof...(pp)] );
}
// unfortunately, I don't know how to avoid this additional overload :(
template < typename T, std::size_t dim>
constexpr c_array<T, dim>
add_to(T s, c_array<T, dim> in, std::size_t index)
{
return add_to(s, in, index, std::false_type{});
}
constexpr c_array<int,5> arr = {1,2,3,4,5};
constexpr c_array<int,5> arr2 = add_to(42, arr, 0); //I want arr2=={43,2,3,4,5}
int main()
{
for(auto const& e : arr2)
{
std::cout << e << ", ";
}
}
Alternative version, slightly awkward usage syntax:
// helper; construct a sequence of non-type template arguments
template < std::size_t... tt_i >
struct seq
{};
template < std::size_t t_n, std::size_t... tt_i >
struct gen_seq
: gen_seq < t_n-1, t_n-1, tt_i...>
{};
template < std::size_t... tt_i >
struct gen_seq < 0, tt_i... >
: seq < tt_i... >
{};
template < std::size_t index, typename T, std::size_t dim,
std::size_t... tt_bef, std::size_t... tt_aft >
constexpr c_array<T, dim>
add_to(T s, c_array<T, dim> in, seq<tt_bef...>, seq<tt_aft...>)
{
return {{ in[tt_bef]..., in[index]+s, in[tt_aft]... }};
}
template < std::size_t index, typename T, std::size_t dim >
constexpr c_array<T, dim>
add_to(T s, c_array<T, dim> in)
{
return add_to<index>(s, in, gen_seq<index>{}, gen_seq<dim-index-1>{});
}
constexpr c_array<int,5> arr = {1,2,3,4,5};
constexpr c_array<int,5> arr2 = add_to<0>(42, arr);