Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this template function overload resolution depend on the declaration order?

Consider the following code:

#include <iostream>

//                     void foo(int* t ) { std::cout << "variant int* t, non-template\n"; }
template<typename T> void foo(T t    ) { std::cout << "variant T t\n"; }
template<>           void foo(int* t ) { std::cout << "variant int* t\n"; }
template<typename T> void foo(T* t   ) { std::cout << "variant T* t\n"; }

int main()
{
    foo( new int{1} );
    return 0;
}

If the non-template version is uncommented, then it is preferred in the overload resolution, as expected. Let's leave it commented.

Curiously, whether the variant with T* t or int* t is chosen in overload resolution depends on the order of declaration.

The output is variant T* t with the lines

template<>           void foo(int* t ) { std::cout << "variant int* t\n"; }
template<typename T> void foo(T* t   ) { std::cout << "variant T* t\n"; }

The output is variant int* t with the swapped lines

template<typename T> void foo(T* t   ) { std::cout << "variant T* t\n"; }
template<>           void foo(int* t ) { std::cout << "variant int* t\n"; }

So it seems that the order of declaration matters. But shouldn't the most special specialization be preferred? What rule applies here?

like image 414
shuhalo Avatar asked Oct 26 '25 14:10

shuhalo


2 Answers

tldr

There are two primary templates here and only primary templates take part in overload resolution. For the call foo(new int{1}), the primary template #2 is a better match. In the second snippet, the second template #2 has a specialization which by definition is more specialized than the primary template #2 and so is used.


Case 1

Here we consider the case when we have the order as:

template<typename T> void foo(T t    )  //#1 primary template
{ 
    std::cout << "variant T t\n"; 
} 
//this specializes the above #1
template<>           void foo(int* t ) 
{ 
    std::cout << "variant int* t\n"; 
}
template<typename T> void foo(T* t   )  //#2 primary template
{ 
    std::cout << "variant T* t\n"; 
}

The important thing to note is that:

a) only primary templates take part in overload resolution. This means that only #1 and #2 take part in overload resolution. This means that for the call foo( new int{1} ), the second template #2 is selected as it is a better match than the other.

b) Note that in this case, the second primary template #2 doesn't have any specialization so the #2 is used and we get the output as variant T*. The specialization that you've provided is for #1 which can't be used because #1 is worst match than #2.


Case 2

Here we consider the declaration order as:

template<typename T> void foo(T t    )  //#1 primary template
{ 
    std::cout << "variant T t\n"; 
} 
template<typename T> void foo(T* t   )  //#2 primary template
{ 
    std::cout << "variant T* t\n"; 
}
//this specializes the above #2
template<>           void foo(int* t ) 
{ 
    std::cout << "variant int* t\n"; 
}

In this case again only the primary templates #1 and #2 take part in overload resolution. And the second primary template #2 is a better match than the first #1.

But the difference is that this time there exists a specialization for the selected #2. And since a specialization is more specialized than the primary template, that is used and so we get the output as variant int*

like image 135
Anoop Rana Avatar answered Oct 29 '25 05:10

Anoop Rana


There are (only) two templates here:

template<typename T> void foo(T t    ) { std::cout << "variant T t\n"; }
template<typename T> void foo(T* t   ) { std::cout << "variant T* t\n"; }

The line

template<>           void foo(int* t ) { std::cout << "variant int* t\n"; }

is a specialization of a template, not itself a template. If it is after the second template it is a specialization of the second template, but if it is between, it specializes the first template.

When you call foo(int *) in main, either template can match, but the second one matches better so that is the one that is used. If (and only if) the specialization is a specialization of that template, it will be used.

like image 42
Chris Dodd Avatar answered Oct 29 '25 06:10

Chris Dodd



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!