The problem is that they don't behave like other variables. You cannot copy them using normal assignment or compare them using the equality operator, you cannot initialize them in member initializer lists, you cannot return them from functions, and they have a nasty habit of decaying to pointers, discarding all size information.
std::array solves all of these issues.
If you're using an AVR, you don't have access to the standard library, so you'll have to install a third-party port, or create your own std::array replacement, in its most basic form, it's just:
template <class T, size_t N>
struct array {
T data[N];
T &operator[](size_t i) { return data[i]; }
const T &operator[](size_t i) const { return data[i]; }
T *begin() { return data; }
const T *begin() const { return data; }
T* end() { return data + N; }
const T* end() const { return data + N; }
};
On all other platforms (ARM, ESP etc.) you can just #include <array>.