A A
A A

Reputation: 23

C++ template specialization problems

I have problems with specialized function templates in C++. I'm writing a comparison function template which will be used in sorting different data types. Here is part of my code:

template < typename T >
bool cmp(T a, T b)
{
    std::cout<<"normal"<<std::endl;
    return(a >= b);
}

template < typename T >
bool cmp(T* a, T* b)
{
    std::cout<<"pointer"<<std::endl;
    return(*a >= *b);
}

so I could sort by values and by pointed values. However, when I try to pass this function into sort:

double* double_array[]={d1,d2,d3,d4,d5};
nsp::sort(double_array, 5, nsp::cmp<double*>);

I get the compile error:

error: no matching function for call to 'sort(double* [5], int, <unresolved overloaded function type>)'|
template argument deduction/substitution failed:|
could not resolve address from overloaded function 'cmp<double*>'|

Why? I am explicitly providing the template type!

For reference, my sort function template looks like:

namespace nsp {
    ...

    template < typename T, typename CMP>
    void sort(T array[], int n, CMP cmp=CMP())
    {
        for(int j = 0;j < n-1; j++)
            for(int i = 0; i < n-1; i++)
              if(cmp(array[i],array[i + 1]))
                  std::swap(array[i], array[i + 1]);
    }
}

Upvotes: 1

Views: 886

Answers (1)

Barry
Barry

Reputation: 303017

The reason you're getting a compile error with "unresolved overloaded function type" is because, quite simply, you are trying to pass an overloaded function to sort(). You provide cmp<double*> but there are still two cmp<double*> functions: the fun that takes two double*s (your first function template) and the one that takes two double**s (your second). It's unclear to the compiler which one you mean.

You could just cast cmp to the one that you want:

static_cast<bool(*)(double*, double*)>(nsp::cmp<double>) // note you want cmp<double>,
                                                         // not cmp<double*>

Note that one source of confusion is that you think you are specializing cmp. You are not. There is no partial specializations of function templates. You overloaded it. The only allowed specializations of function templates are explicit:

template <>
bool cmp(double* a, double* b) {
    std::cout<<"pointer"<<std::endl;
    return(*a >= *b);
}

That would make nsp::cmp<double*> unambiguous and would do exactly what you would expect. In this case. You would have to do this for every type separately. Instead, you could provide a class template comparator because class templates can be partially specialized:

template <typename T> struct Cmp { .. };     // "normal"
template <typename T> struct Cmp<T*> { .. }; // "pointer"

That way, you can just pass nsp::Cmp<double*>(), which is in my opinion much cleaner.

Upvotes: 3

Related Questions