Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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*)
like image 573
Jordan Avatar asked Jan 11 '17 15:01

Jordan


2 Answers

Explanations in comments:

// the 1st primary function template, overloaded function template
template<typename T>
void foo(T t)

// full template specialization of the 1st function template with T = int*
template<>
void foo<int*>(int* l)

// the 2nd primary function template, overloaded function template
template<typename T>
void foo(T* l)

// non-template function, overloaded function
void foo(int* l)

int main()
{
    int x = 0;
    foo(x);  // only match the 1st function template; the others take pointer as parameter
    foo(&x); // call the non-template function, which is prior to templates in overload resolution
    return 0;
}

See more details about overload resolution and explicit (full) template specialization.

like image 104
songyuanyao Avatar answered Sep 18 '22 08:09

songyuanyao


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.

like image 34
Rakete1111 Avatar answered Sep 20 '22 08:09

Rakete1111