Is this a correct implementation/use of move semantics?
Yes BUT.

The std::array itself is not moveable. But it is still optized for move semantics when its content type T is moveable. So it will move each of its internal elements rather than copy them. But your function limits the type of T to std::is_arithmetic which is only defined for built-in integers and floats. Moving integers and floats is the same as copying them. So you get no real benefit.

But lets take this a step further.
If you remove the static_assert so it can be used by any type that supports the operator* etc.. then you have a usability issue.

When you do a multiplication like this you destroy the original array (Its content has been moved so there is no way to know what the elements are or if they are usable. About the only thing you can do is reset them to a specific state).

#include &lt;array&gt;

int main()
{
    std::array&lt;MyMathType, 5&gt;  a = initArray();
    std::array&lt;MyMathType, 5&gt;  c;

    // Your code moves the content of a here.
    c = a * 5;

    // So at this point the content of a is in an undefined state
    // So you can not rely on what is in `a` or use it in ANY way that would
    // need the content to be in a defined state (all you can really do is reset).
    //
    // This is not what I would expect of `operator*`
    // So it is quite easy to make mistakes with this code.
}