For example, instead of
void shared_ptr::reset() noexcept;
template
void shared_ptr::reset(Y* ptr);
one may think of
While the design choices of the other answers are all valid, they do assume one thing that does not fully apply here: Semantic equivalence!
void shared_ptr::reset() noexcept;
// ^^^^^^^^
template
void shared_ptr::reset(Y* ptr);
The first overload is noexcept, while the second overload isn't. There is no way to decide the noexcept-ness based on the runtime value of the argument, so the different overloads are needed.
Some background information about the reason for the different noexcept specifications: reset() does not throw since it is assumed that the destructor of the previously contained object does not throw. But the second overload might additionally need to allocate a new control block for the shared pointer state, which will throw std::bad_alloc if the allocation fails. (And resetting to a nullptr can be done without allocating a control block.)