Search code examples
c++templatesoverloadingtemplate-specializationoverload-resolution

Function specialisation / overloading rules example


I understand you can't partially specialise a function template, I also understand typical function overloading.

Where I need help is in grokking the difference between the below 4 foo() functions. I expect a few of them are different syntax for exactly the same thing?

Could somebody more knowledgeable explain for each function what exactly is happening with regards to is it a template specialisation or overload, and how does the c++ compiler determine what to invoke?

//(1)
template<typename T>
void foo(T t)
{
    cout << "template<T> foo(T) " << endl;
}

//(2)
template<>
void foo<int*>(int* l)
{
    cout << "template<> foo<int*>(int*) " << endl;
}

//(3)
template<typename T>
void foo(T* l)
{
    cout << "template<T> foo(T*) " << endl;
}

//(4)
void foo(int* l)
{
    cout << "normal overload foo(int*) " << endl;
}

int main()
{
    int x = 0;
    foo(x);
    foo(&x);
    return 0;
}

Program Output:

template<T> foo(T)
normal overload foo(int*)

Solution

  • Let's go through the first call, foo(x).

    int can't be written as a pointer, unable to deduce parameter, next

    void foo(int* l);
    

    Can't convert int to int* implicitly, next

    template<typename T>
    void foo(T t);
    

    That seems like a good match, like remember it as 2). Next

    template<>
    void foo<int*>(int* l);
    

    Can't convert int to int* implicitly, next

    template<typename T>
    void foo(T* l)
    

    So, the only possible match is 2), and so template<T> foo(T) is the output.


    Second call, foo(&x).

    void foo(int* l);
    

    A non-template function which matches perfectly the type of x. Let's remember this one.

    template<typename T>
    void foo(T t);
    

    Good match! But the previous one is still better, next

    template<>
    void foo<int*>(int* l);
    

    Oh, a specialization of the previous template which exactly matches the type, that's better, but 1) is still the better match. Next

    template<typename T>
    void foo(T* l)
    

    Better than a specialization, a template without, but doesn't beat the non-template one.

    And so, in the end, the non-template function is called. Non-templates are always better than templates.