Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sum two std::array of non-default-constructible types

Tags:

c++

std

If I want to write a function summing two std::array, I would do something like:

template<class T, std::size_t N>
auto sum(const std::array<T, N>& a, const std::array<T, N>& b)
{
    std::array< decltype(a[0] + b[0]), N> result; //the underlying type is not necessarily T
    for (std::size_t i = 0; i < N; ++i)
    {
        result[i] = a[i] + b[i];
    }
    return result;
} 

How would I write this function in case decltype(a[0] + b[0]) is not default-constructible?

Here is an example on compiler explorer: https://godbolt.org/z/qndGfhehM

Ideally, I want to directly create and initialize the std::array, but I failed to write a function for any N.

I would like to rely only on a C++ standard.

I guess the implementation can be achieved with an intermediate std::vector, but it would require copies.

I tried to write a recursive template function such as:

template<class T, std::size_t N>
auto operator+(const std::array<T, N>& a, const std::array<T, N>& b)
{
    if constexpr (N > 1)
    {
        return {a[0] + b[0], ???};
    }
    else
    {
        return {a[0] + b[0]};
    }
}

but I don't know what to write instead of the ???.

I am aware that std::index_sequence exists, but I don't know how to use it in this case.

like image 603
alxbilger Avatar asked Jul 14 '26 01:07

alxbilger


2 Answers

Using std::index_sequence is a two-step process:

Create it and pass it to a helper which uses the indices for your task.
A generic lambda with explicit template-arguments is enough for that (for earlier standards, use a normal function and more arguments):

template <class T, std::size_t N>
auto operator+(const std::array<T, N>& a, const std::array<T, N>& b)
{
    return [&]<std::size_t... Is>(std::index_sequence<Is...>){
        return std::array<decltype(a[0] + b[0]), N>{(a[Is] + b[Is])...};
    }(std::make_index_sequence<N>());
}
like image 145
Deduplicator Avatar answered Jul 15 '26 16:07

Deduplicator


Something along these lines:

template <typename T, std::size_t N, std::size_t... Is>
auto sum_helper(const std::array<T, N>& a, const std::array<T, N>& b,
                std::index_sequence<Is...>) {
    return std::array<decltype(a[0] + b[0]), N>{(a[Is] + b[Is])...};
}

template<class T, std::size_t N>
auto sum(const std::array<T, N>& a, const std::array<T, N>& b)
{
    return sum_helper(a, b, std::make_index_sequence<N>{});
} 

Demo

like image 31
Igor Tandetnik Avatar answered Jul 15 '26 15:07

Igor Tandetnik