In theory erase could return a move iterator, meaning that you could omit the call to std::move. This wouldn't be backwards compatible though so not going to happen.
There is no erase that takes an index, so I assume that n = a.end(). Also it is missing a dereference:
a[i] = std::move(*a.erase(a.end()-1));
but erasing the one-before-the-end returns the (new) end iterator, which obviously is not referenceable. In general, after calling erase, it is too late to access the erased element.
You want something like:
template<class Container, class Iter>
auto erase_and_return(Container&& c, Iter pos)
{
auto x = std::move(*pos);
c.erase(pos);
return x;
}
Also in the general case it doesn't make sense for erase to return a move iterator.
I think that would just call the copy assignment operator, would it not?
For correctness you would probably then follow up with a pop_back to keep the vector right-sized.
Actually you'd probably want to do:
a[i] = std::move(a[n - 1]);
Then follow up with pop_back.
Best would probably be:
a[i] = std::move(a.erase(n-1));