I want to write a constexpr function, that reduces a given std::array
with a binary operation. I.e. a function which implements
template <typename T, std::size_t N>
reduce(std::array<T, N>, binary_function);
To keep things simple I want to start with addition. E.g.
sum(std::array<int, 5>{{1,2,3,4,5}}); // returns 15.
What I got so far.
I use the usual indexing trick to index array elements. I.e. generate a int
sequence, that can be used for indexing with parameter list-expansion.
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...> {}; // gen_seq<4> --> seq<0, 1, 2, 3>
The sum
function is then defined through variadic template recursion.
// The edge-condition: array of one element.
template <typename T>
constexpr T sum(std::array<T, 1> arr, decltype(gen_seq<0>{})) {
return std::get<0>(arr);
}
// The recursion.
template <typename T, std::size_t N, int... Is>
constexpr auto sum(std::array<T, N> arr, seq<Is...>) -> decltype(T() + T()) {
return sum(std::array<T, N - 1>{ { std::get<Is>(arr)... } },
gen_seq<N - 2>()) +
std::get<N - 1>(arr);
}
// The interface - hides the indexing trick.
template <typename T, std::size_t N>
constexpr auto sum(std::array<T, N> arr)
-> decltype(sum(arr, gen_seq<N - 1>{})) {
return sum(arr, gen_seq<N - 1>{});
}
Here you can see it in action.
Questions
This implementation works. However, I do have a few questions at this stage.
- Is there any way, I can add perfect-forward to this function? And does that even make sense? Or should I declare those arrays const-references?
- The assumption so far is, that the return-type of the reduction is
decltype(T()+T())
. I.e. what you get when you add two elements. While this should be true for addition in most cases, it might no longer be true for a general reduction. Is there a way, of getting the type ofa[0] + (a[1] + (a[2] + ... ) )
? I tried something like this, but I don't know how I can produce a template parameter list of<T, T, T, ...>
.