Consider
Class Wow{
public:
//main metod
template<typename T>
void foo(T t){
cout << t << endl;
}
template<>
void foo<int>(int t){
cout << "specialization" << endl;
}
void foo(int t){
cout << "overloading" << endl;
}
}
and the main is
Wow wow;
wow.foo(2.2);
wow.foo(1);
this outputs
2.2
overloading
My question is why does that even compile?
practically, foo is defined twice as void foo(int).
1) why does this pass?
2) why does the compiler choose the overloading one?
Thanks
1) Because there is no problem here. There is template function, function template specialization and overloading. You can call template specialization like this:
wow.foo<int>(3);
2) Overload has better match, than template specialization, if compiler can call this function with arg.
n4926 13.3.3/1.7
Given these definitions, a viable function F1 is defined to be a
better function than another viable function F2 if for all arguments
i, ICSi(F1) is not a worse conversion sequence than ICSi(F2) , and
then
F1 is not a function template specialization and F2 is a function
template specialization
Related
I have two template functions:
template <typename T>
void func(T a)
{ std::cout << "func(T a)" << std::endl; }
template <typename T>
void func(int a)
{ std::cout << "func(int a)" << std::endl; }
And calling func which different method will lead to different result:
func(1); // call func(T a)
func<int>(1); // call func(int a)
Here is the demo. I originally thought that func(1) and func<int>(1) are identical, but it seems that I was wrong. Does compiler treat func(1) and func<int>(1) differently? Thanks for any help!
The call func<int>(1); chooses the second overload because it is more specialized.
The call func(1); can't choose the second overload, because the second overload has a template parameter T which is neither given a template argument explicitly (as in func<int>(1);), nor can be deduced from the function parameter/argument pair (as T in the first overload can from the argument 1 to the T a parameter). If a template argument can't be deduced and isn't explicitly given, then the overload is non-viable in overload resolution. The only remaining overload is the first one, which is then chosen.
Consider the code:
#include <iostream>
template <typename T>
void f(T)
{
std::cout << "Version 1" << std::endl;
}
template <typename T>
void f(T *)
{
std::cout << "Version 2" << std::endl;
}
template <>
void f<>(int *)
{
std::cout << "Version 3" << std::endl;
}
int main()
{
int *p = nullptr;
f(p);
return 0;
}
This code will output Version 3. What is happening is that function overloading rules look at the first two versions of void f (the third version is a specialization and does not participate in the overload), and decides that the second version is the better version. Once that decision is made, we then see if any specializations exist for the second version. There is, and we use it.
My question, then, is: How did the compiler know that my explicit specialization was a specialization of the second overload and not the first one? I have not provided it with a template parameter for it to make that choice. Is it simply the case that deciding which function to specialize follows a similar/the same rule as deciding which overload to call (if it were calling the function)? That would make some sense...
There is that example in template_argument_deduction#Explicit_instantiation
Template argument deduction is used in explicit instantiations, explicit specializations, and those friend declarations where the declarator-id happens to refer to a specialization of a function template (for example, friend ostream& operator<< <> (...)), if not all template arguments are explicitly specified or defaulted, template argument deduction is used to determine which template's specialization is referred to.
P is the type of the function template that is being considered as a potential match, and A is the function type from the declaration. If there are no matches or more than one match (after partial ordering), the function declaration is ill-formed:
template<class X> void f(X a); // 1st template f
template<class X> void f(X* a); // 2nd template f
template<> void f<>(int* a) { } // explicit specialization of f
// P1 = void(X), A1 = void(int*): deduced X = int*, f<int*>(int*)
// P2 = void(X*), A2 = void(int*): deduced X = int, f<int>(int*)
// f<int*>(int*) and f<int>(int*) are then submitted to partial ordering
// which selects f<int>(int*) as the more specialized template
Consider the following code:
#include <iostream>
#include <type_traits>
template <typename T>
class A
{
public:
// Allow func to be called if T is the const version of T2
// e.g., T is 'int const' and T2 is 'int'
template <typename T2,
typename = typename std::enable_if<
std::is_same<T, T2 const>::value>::type>
void func(A<T2> const &)
{
std::cout << "Conversion" << std::endl;
}
// Allow func to be called for same version of T
void func(A const &)
{
std::cout << "No conversion" << std::endl;
}
};
int main()
{
A<int const> a;
a.func(A<int const>{});
return 0;
}
This code, when compiled with GCC-8.3 compiles and produces the output No conversion - it selected the version of func that does not use std::enable_if. However, if I comment out the second version of func, it will still compile and now produce the output Conversion. In other words, both versions of func within A are usable for this method. Given that both overloads are viable, what specific rule is the compiler using to select func(A const &) over the other version (func(A<T2> const &))?
The rule is that if a non function template and a function template specialization have the same signature, then the non function template is chosen over the template specialization. This can be found in [over.match.best]/2
Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
[...]
F1 is not a function template specialization and F2 is a function template specialization [...]
You can read about overload resolution here. In particular
If any candidate is a function template, its specializations are generated using template argument deduction, and such specializations are treated just like non-template functions except where specified otherwise in the tie-breaker rules.
And then
Best viable function
For each pair of viable function F1 and F2, the implicit conversion sequences from the i-th argument to i-th parameter are ranked to determine which one is better [...]
F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and
[...]
4) [...] F1 is a non-template function while F2 is a template specialization
Basically the same rules apply in this simpler example:
#include<iostream>
template <typename T>
void foo(T i) { std::cout << "template" ; }
void foo(int i) { std::cout << "non template"; }
int main() {
foo(1); // non template
}
Considering this code:
template <class T>
void f(T p) { //(1)
cout << "Second" << endl;
}
template <>
void f(int *p) { //(2)
cout << "Third" << endl;
}
template <class T>
void f(T* p) { //(3)
cout << "First" << endl;
}
A call such as int *p; f(p); will output First.
If the order of the declarations is changed, like this:
template <class T>
void f(T* p) { //(3)
cout << "First" << endl;
}
template <class T>
void f(T p) { //(1)
cout << "Second" << endl;
}
template <>
void f(int *p) { //(2)
cout << "Third" << endl;
}
the same call (int *p; f(p);) will output Third.
I read about the way in which function template overload resolution takes places: first the resolution considers only non-template functions and the underlying base templates. After the "most specialized" one is chosen, if it is a template function and it has a specialization for the parameters which were deduced (or explicitly specified), that specialization is called.
Now my question is: how it is decided for which underlying base template a function is a specialization? In my example, for which function template overload ( (1) or (3) ) is (2) a specialization?
My guess is that when a specialization is declared, the templates already declared are considered, and from those the most "specialized" (whose parameters are "closest" to this specialization) is chosen. Is this correct? Also, could you point me to where this is specified in the standard?
It prints "First" because the order of declaration affects which template you in fact specialize.
Your example has two function templates, which overload the same name. In the first case, you specialize void f(T p), because it's the only template seen so far.
In the second case, it's void f(T* p) that's specialized. So yes, your guess is correct. The specifics are at [temp.deduct.decl/1]:
In a declaration whose declarator-id refers to a specialization of a
function template, template argument deduction is performed to
identify the specialization to which the declaration refers.
Specifically, this is done for explicit instantiations, explicit
specializations, and certain friend declarations. [...]
And that includes the partial ordering of the function templates. However, partial ordering only applies to the available function template declarations at the point you introduce your specialization.
And the standard warns at [temp.expl.spec/7]:
The placement of explicit specialization declarations for function templates, [...] , can affect whether a program is well-formed
according to the relative positioning of the explicit specialization
declarations and their points of instantiation in the translation unit
as specified above and below. When writing a specialization, be
careful about its location; or to make it compile will be such a trial
as to kindle its self-immolation.
#include <iostream>
template <class T>
void foo(T) {
std::cout << "foo(T)" << std::endl;
}
template <class T>
void foo(T*) { //#3
std::cout << "foo(T*)" << std::endl;
}
#define TEST
#ifdef TEST
template <>
void foo(int*) { //#1
std::cout << "foo(int*)" << std::endl;
}
#else
template <>
void foo<int*>(int*) { //#2
std::cout << "foo<int*>(int*)" << std::endl;
}
#endif
int main(int argc, char **argv) {
int* p = 0;
foo(p);
return 0;
}
What is the difference between #1 and #2 above? If I define TEST, then #1 works, but if I comment it out, #3 works. Which is the right way to write function template specialization here?
#1 declares a function template specialization of #3 and automatically deduces the template parameters. #2 is a specialization of the first template you defined (the one without number, let's call it #0) for T=int*. It can't be a specialization of #3 because replacing T with the specified int* there would lead to a int** parameter.
When you call foo, overload resolution now first picks the best fitting base template, then checks that template for any existing specializations. With TEST defined, there are two base templates (#0 and #3) and #3 is a better match and gets selected. Then the compiler checks for specializations of that template, and #1 is a better fit and is being called.
Without TEST defined, there are still two base templates (#0 and #3) and #3 is a better match and gets selected. Then the compiler checks for specializations of that template, but since #2 specializes #0 and not #3, it is not considered and #3 ends of being called.
This is the classical example of Why not Specialize Function Templates. The problems are explained in more detail there.
The simple solution is to not specialize function templates at all, but simply add new overloads for the special types:
// no template, just a normal function
void foo(int*) {
std::cout << "foo(int*)" << std::endl;
}
For function template specializations you can explicitly list the template arguments but you don't have to if the template arguments are deduced. If you don't specify the template arguments, they are deduced by the compiler using the same rules as overload resolution. For deciding which function overload is to be chosen, the compiler starts with looking only at the primary templates (which are selected by some magical process in the first place). Looking at the two available primary templates
template <typename T> void foo(T);
template <typename T> void foo(T*);
the latter is a better match for a pointer argument. Once the proper primary template is found, the compiler looks for potential specializations of this primary template. However, your example #2 actually is not a specialization of function template taking a pointer argument although it involves a pointer argument. If you take the primary declaration
template <typename T> void foo(T*);
and you replace T by the explicitly specified template argument int* you get
template <> void foo<int*>(int**);
That is, the declaration
template <> void foo<int*>(int*);
is something different. You probably just want to lose the pointer when specifying the template argument:
template <> void foo<int>(int*);
I can't really tell which function #2 is supposed to specialize, or exactly how the extremely complicated overload resolution rules would select the function to call.
I do know that you most often don't need to specialize functions, but can rely on overloading instead. To get a function for int* you just need
void foo(int*) {
std::cout << "foo(int*)" << std::endl;
}
A non-template function will be preferred over templates, as long as the parameter matches.