Generic Merge Sort in C++
While your merge step in mergeSort works it should be put into its own function:

// Exercise: make `my_merge` even more generic
template &lt;typename Iterator, typename OutputIterator&gt;
void my_merge(Iterator first1, Iterator last1,
              Iterator first2, Iterator last2,
              OutputIterator out)
{
    while (first1 != last1 &amp;&amp; first2 != last2) {
        if (*first1 &lt; *first2) {
            *out++ = *first1++;
        } else {
            *out++ = *first2++;
        }
    }

    while(first1 != last1) {
        *out++ = *first1++;
    }
    while(first2 != last2) {
        *out++ = *first2++;
    }
}

template&lt;typename T&gt;
T mergeSort(typename T::iterator begin, typename T::iterator end) {
    auto n = end - begin;
    if (n &lt; 2) {
        return T(begin, end);
    }
    auto firstHalf  = mergeSort&lt;T&gt;(begin, begin + n/2);
    auto secondHalf = mergeSort&lt;T&gt;(begin + n/2, end);

    T merged;

    my_merge(firstHalf.begin(), firstHalf.end(), 
             secondHalf.begin(), secondHalf.end(),
             std::back_inserter(merged));
    return merged;
}


Note that I had to call my_merge that way since std already contains std::merge, which we can use instead:

template&lt;typename T&gt;
T mergeSort(typename T::iterator begin, typename T::iterator end) {
    auto n = end - begin;
    if (n &lt; 2) {
        return T(begin, end);
    }
    auto firstHalf  = mergeSort&lt;T&gt;(begin, begin + n/2);
    auto secondHalf = mergeSort&lt;T&gt;(begin + n/2, end);

    T merged;

    std::merge(firstHalf.begin(), firstHalf.end(), 
               secondHalf.begin(), secondHalf.end(),
               std::back_inserter(merged));
    return merged;
}


The merge and the parameters begin and end are good examples why using namespace std has to be handled with care. All those names are already in std. Use using namespace std only if you know the risks.

That being said, your generic variant will only work with random access iterators. If you want to make it more generic, you have to use std::distance and std::next instead of end - begin and begin + n/2:

template&lt;typename T&gt;
T mergeSort(typename T::iterator begin, typename T::iterator end) {
    const auto n = std::distance(begin, end);

    if (n &lt; 2) {
        return T(begin, end);
    }
    const auto midpoint = std::next(begin, n / 2);

    const auto firstHalf  = mergeSort&lt;T&gt;(begin, midpoint);
    const auto secondHalf = mergeSort&lt;T&gt;(midpoint, end);

    T merged;

    std::merge(firstHalf.begin(), firstHalf.end(), 
               secondHalf.begin(), secondHalf.end(),
               std::back_inserter(merged));
    return merged;
}


Even if you don't want to use std::next re-use the midpoint.