13

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?

2 Answers 2

21

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>());
}
Sign up to request clarification or add additional context in comments.

7 Comments

Wow, pure magic to me! C++ sure has come a long way in recent year. Thanks!
It is worth adding that for c++11 there are available efficient implementations of integer_sequence e.g. this one as it unfortunately does not come out of the box.
@kalj: actually, there isn't much magic. Maybe it is natural to me because I posted this answer which led to the relevant proposal. ;-)
@DietmarKühl, well if this was magic that answer is pure witchcraft to me. So much cool stuff to learn though!
Okay, it works with some slight modifications. Turns out N must be std::size_t, and there is also a small typo in that append should return an array of size N+1. You might want to update this.
|
1

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>());
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.