3
template<typename T>
void Merge_Sort(vector<T>::iterator begin, vector<T>::iterator end) {

size_t length = end - begin;
if (1 >= length) return;

size_t mid = length/2;

Merge_Sort(begin, begin + mid);
Merge_Sort(begin + mid, end);
inplace_merge(begin, begin + mid, end);
}

I am trying to template-ize the function but getting the error that I am missing the typename prior to vector::iterator. Could anybody have an idea about making this function template?

To sum, I am trying to make iterator parameter as template.

  • 2
    `typename` may be handy for this problem, but why not just make the iterator the template parameter itself. (or was that the point, sorry if I misunderstood). – WhozCraig Aug 08 '13 at 23:48

3 Answers3

7

You should use std::distance, std::next (or std::advance in c++03) to do the calculations.

Also, hardcoding vector is quite the opposite of making it generic, IYAM

template<typename It>
void Merge_Sort(It begin, It end) {
    size_t length = std::distance(begin, end);
    if (1 >= length) return;

    size_t mid = length/2;

    auto pivot = std::next(begin, mid);

    Merge_Sort(begin, pivot);
    Merge_Sort(pivot, end);
    inplace_merge(begin, pivot, end);
}

For completeness, here's one that integrates the Comparison predicate and sorts in descending order live on Coliru

#include <algorithm>
#include <vector>
#include <iterator>

template<typename It, 
    typename Cmp = typename std::less<typename std::iterator_traits<It>::value_type> >
void Merge_Sort(It begin, It end, Cmp cmp = Cmp()) {
    size_t length = std::distance(begin, end);
    if (length<2) return;

    size_t mid = length/2;

    auto pivot = std::next(begin, mid);

    Merge_Sort(begin, pivot, cmp);
    Merge_Sort(pivot, end, cmp);
    std::inplace_merge(begin, pivot, end, cmp);
}

#include <iostream>

int main()
{
    std::vector<int> v { 1,3,7,-3,4,99,-13 };

    Merge_Sort(begin(v), end(v), std::greater<int>());

    for(auto i : v)
        std::cout << i << " ";
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    ..and +1 for `std::next()` (I'm always learning something new; thanks!). Shouldn't there be commas in those? – WhozCraig Aug 08 '13 at 23:54
  • 1
    Have added the comparator and a test/demo program [live on Coliru](http://coliru.stacked-crooked.com/view?id=207206d0b640c2a9a3bbc1c72489fa1d-bff069f172c3f5c3bc4a5e28d7ac9796) – sehe Aug 09 '13 at 00:12
  • Hello! Thanks for your answer. I am new to C++. Would you be kind enough to provide a link on what you have done with the second template argument?? (I have never seen something like that before) – Gregor Hartl Watters Apr 09 '22 at 19:00
  • 1
    @GregorWattersHärtl It's another type argument that allows the caller to specify a comparator type. The `= ...` story specifies a default value. It's a little bit complex because we have to deduce the value-type of the iterator range (using `iterator_traits` in this example). Since c++14 we can simplify using [`less`](https://en.cppreference.com/w/cpp/utility/functional/less_void) so it would be much more straightforward: http://coliru.stacked-crooked.com/a/f5eca1407239a8f2, also note the default isn't used in the example: http://coliru.stacked-crooked.com/a/a4694f8475964e41 – sehe Apr 09 '22 at 21:11
  • @sehe oh wow thank you so much for the explanation!! I'll read up on that right now. Cheers. – Gregor Hartl Watters Apr 10 '22 at 14:54
2

I didn't just hammer this out. I had it in an old source file, but I think this was what you were trying to do. I've added two additional interfaces for sorting fixed arrays and arbitrary based-pointers with a specified length. Hope it helps:

#include <iterator>
#include <algorithm>

// general mergesort algorithm
template <
  typename Iterator,
  typename Compare=std::less<typename std::iterator_traits<Iterator>::value_type>
>
void mergesort(Iterator first, Iterator last, const Compare& cmp=Compare())
{
    size_t n = std::distance(first, last)/2;
    if (n == 0)
        return;

    Iterator mid = std::next(first, n);
    mergesort(first, mid, cmp);
    mergesort(mid, last, cmp);
    std::inplace_merge(first, mid, last, cmp);
}

// front-loader for static arrays
template<typename Item, size_t N>
void mergesort(Item (&ar)[N])
{
    mergesort(std::begin(ar), std::end(ar));
}

// front-loader for size-specified base-pointer arrays
template<typename Item>
void mergesort(Item *ptr, size_t N)
{
    mergesort(ptr, ptr+N);
}
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • Ha, I _did_ just hammer it out, and I didn't assume random-access iterators. Hmm. Perhaps inplace_merge requires them anyways ... :| – sehe Aug 08 '13 at 23:51
  • @sehe lol. I never really checked, this was back when I was exploring the fun side of `iterator_traits<>` (which f'ing *rocks*, btw). – WhozCraig Aug 08 '13 at 23:52
  • +1 for actually including a comparator – sehe Aug 08 '13 at 23:53
1

getting the error that I am missing the typename prior to vector::iterator

As the error says, you're missing typename before vector<T>::iterator:

void Merge_Sort(typename vector<T>::iterator begin, typename vector<T>::iterator end)
                ^^^^^^^^                            ^^^^^^^^

This is needed when specifying a dependent type name: the name of a type nested in a template, that depends on the template arguments. Until the template is instantiated, the compiler doesn't know what the name represents, so you must tell it that it names a type.

To sum, I am trying to make iterator parameter as template.

Then it might be better to do just that:

template <typename Iter>
void Merge_Sort(Iter begin, Iter end);
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Thanks!!!! But could anybody know why I do not have to put anything like Merge_Sort when I actually call this function? Is it because it is NOT class template, but function template? I remember reading something like this in textbook but I can't find it now. –  Aug 09 '13 at 00:07
  • 2
    Yes, it's because it's a function template. It's called "template argument deduction" - if the template arguments can be deduced from the types of the function arguments, then you don't have to give the template arguments. – Mike Seymour Aug 09 '13 at 00:11