The following code defines an operator+
between std::array
of arbitrary type. The implementation consists in defining an auxiliary routine op2
that takes a generic callable operator and applies it to every element of the array, via template recursion.
#include <array>
#include <functional>
#include <iostream>
template <typename T, std::size_t N>
std::array<T, N> operator+(const std::array<T, N>& lhs, const std::array<T, N>& rhs);
template <std::size_t Index = 0, typename T, std::size_t N, class F>
void op2(const std::array<T, N>& lhs, const std::array<T, N>& rhs, std::array<T, N>& res, F&& op);
template <typename T, std::size_t N>
std::array<T, N> operator+(const std::array<T, N>& lhs, const std::array<T, N>& rhs)
{
std::array<T, N> res;
op2(lhs, rhs, res, std::plus{});
return res;
}
template <std::size_t Index, typename T, std::size_t N, class F>
void op2(const std::array<T, N>& lhs, const std::array<T, N>& rhs, std::array<T, N>& res, F&& op)
{
std::get<Index>(res) = op(std::get<Index>(lhs), std::get<Index>(rhs));
if constexpr (Index < (N - 1))
op2<Index + 1>(lhs, rhs, res, std::forward<F>(op));
}
template <std::size_t N>
void print_array(const std::array<int, N>& a)
{
for (int x : a)
std::cout << x << ' ';
std::cout << '\n';
}
int main(){
std::array<int, 3> a{1, 2, 3};
std::array<int, 3> b{2, 2, 1};
print_array(a + b);
std::array<std::array<int, 3>, 2> c{a, b};
std::array<std::array<int, 3>, 2> d{a, b};
auto x = c + d; // Error: no match for call to std::plus<void>
return 0;
}
See it Live on Coliru.
The first part works fine and computes the sum of the arrays of int a
and b
.
Next, c
and d
are std::array
of std::array<int,3>
. The program fails to compile because it cannot find a match for std::plus
between components of c
and d
, that is, std::plus::operator()
cannot understand how to sum two std::array<int, 3>
.
A workaround is to define operator+
as
template <typename T, std::size_t N>
std::array<T, N> operator+(const std::array<T, N>& lhs, const std::array<T, N>& rhs)
{
std::array<T, N> res;
op2(lhs, rhs, res, [](const auto& lhs, const auto& rhs) { return lhs + rhs; });
return res;
}
See it Live on Coliru.
Accordind to the reference std::plus=std::plus<void>
should simply return the sum result with parameter and return type deduced, pretty much similar to what the anonymous lambda does.
Why the solution with std::plus
does not compile?
The same problem occurs in the following simplified demo:
std::array<int, 3> a{1, 2, 3};
std::array<int, 3> b{2, 2, 1};
print_array(std::plus{}(a, b));
Internally, std::plus
invokes operator+
. But since it is invoked in the std::namespace
, it may not find your custom operator+
defined outside of this namespace.
Generally, operators for some class should be defined in the namespace where that class is defined. But in the case of std::array
, this is not possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With