function template specialization failed? - c++

#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.

Related

Rule for which function overload to specialize

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

C++ function template specialization and overloading

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.

C++ function template specialization declarations and template arguments; none vs. <> vs. <type>

When studying function templates, I see specializations declared in different ways:
template<> void f(argtype) {}
template<> void f<>(argtype) {}
template<> void f<argtype>(argtype) {}
... and I wonder about the differences between these. Given the below example with template functions with and without parameter, I have a few questions.
#include <iostream>
#include <typeinfo>
//Function print1 WITH function parameter---------------------------------------------
template<class T>
void print1(T) { std::cout << "Primary template for print1() with type " << typeid(T).name() << std::endl; }
template<>
void print1<int>(int) { std::cout << "Specialization for print1<int>(int)" << std::endl; }
//Not allowed, deduced to be the same as print1<int>(int)
/*template<>
void print1<>(int) { std::cout << "Specialization for print1<>(int)" << std::endl; }*/
//Not allowed, deduced to be the same as print1<int>(int)
/*template<>
void print1(int) { std::cout << "Specialization for print1(int)" << std::endl; }*/
//Function print2 WITHOUT function parameter------------------------------------------
/*Not allowed together with print<>(); compiler complains:
t2.cpp:29:6: error: template-id 'print2<>' for 'void print2()' does not match any template declaration*/
/*template<class T>
void print2() { std::cout << "Primary template for print2()" << std::endl; }*/
template<class T = short> //Declaration of print2<>() now ok in conjunction with print2<>()
void print2() { std::cout << "Primary template for print2()" << std::endl; }
template<>
void print2<int>() { std::cout << "Specialization for print2<int>()" << std::endl; }
template<>
void print2<>() { std::cout << "Specialization for print2<>()" << std::endl; }
int main() {
//These three work in the same way, no matter which call method we use, so far so good
print1(10);
print1<>(10);
print1<int>(10);
print1(true);
print1<>(true);
print1<bool>(true);
print2(); //Triggers print2<>(), a bit unexpectedly, should trigger print2<short>() (primary template)
print2<>(); //Triggers print2<>(), a bit unexpectedly, should trigger print2<short>() (primary template)
print2<bool>(); //Triggers print2<bool>() primary template
print2<short>(); //Triggers print2<>(), should definately trigger primary template for print2()
print2<int>(); //Triggers print2<int>() specialization
return 0;
}
outputs:
Specialization for print1<int>(int)
Specialization for print1<int>(int)
Specialization for print1<int>(int)
Primary template for print1() with type b
Primary template for print1() with type b
Primary template for print1() with type b
Specialization for print2<>()
Specialization for print2<>()
Primary template for print2()
Specialization for print2<>()
Specialization for print2<int>()
What special meaning is derived from leaving the template specialization argument empty, non-existent or with the specialized type and how does it effect the outcome?
It seems that with a function argument, this specification is superfluous and the compiler deduces it no matter how it's specified (with the result that equivalent explicit specifications become unallowed redeclarations).
I understand that given a function without parameters, the specialized template argument is needed explicitly in declaration to specify for which instantiation the defined function
applies to (since it can't be deduced otherwise). But the meaning seems to imply something more in this case and the "empty" specialization (<>) is triggered in a somewhat unforeseen ways. How come?
Why do I have to have a default template parameter when specializing print2 with print2<>() but not without it?
What special meaning is derived from leaving the template
specialization argument empty, non-existent or with the specialized
type and how does it effect the outcome?
If you do provide a template argument list completely then you're simply explicitly specializing the function template for a given set of template arguments.
If you provide arguments for a (possibly empty) subset of the template parameters then you are explicitly specializing the function template for a set of arguments that has to be deduced. According to [temp.deduct.decl]:
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 (14.7.2),
explicit specializations (14.7.3), and certain friend declarations
(14.5.4). […]. In all these cases, P is the type of the function
template being considered as a potential match and A is […] the
function type from the declaration […]. The deduction is done as
described in 14.8.2.5.
If, for the set of function templates so considered, there is either
no match or more than one match after partial ordering has been
considered (14.5.6.2), deduction fails and, in the declaration cases,
the program is ill-formed.
So for every parameter for which no argument was given, or in the case where no list is specified at all, template argument deduction is done for each corresponding parameter of the specialization and its counterpart from the primary template. The process is described in §14.8.2.5 and works just as if we called the primary template with the provided template argument list as the template arguments and objects of the types of the parameters in the specialization as the function arguments. You should be familiar with the fact that one can call a function template with some of the template arguments specified, e.g.
template <typename A, typename B> void foo(A, B);
foo(7684, 48.);
foo<int>(7684, 48.);
foo<int, double>(7684, 48.);
That works equivalently for explicit specializations:
template <typename T, typename U>
void foo(T, U) {}
// Both template arguments have to be deduced.
template<> void foo(double, float);
// The *exact* same as above.
// template<> void foo<>(double, float);
// Second template argument has to be deduced by type.
// If we call foo<int>(int(), float()) then the deduced specialization is
// foo<int, float>, thus U=float.
template<> void foo<int>(int, float);
template<> void foo<int, int>(int, int);
This can also be applied to overloads of a function template. In an attempt to find the primary template a specialization is corresponding to, the most specialized one is chosen.
template <typename T, typename U>
void foo(T&, U&) {}
template <typename T, typename U>
void foo(T const&, U&) {}
// Specializes the second overload because it is more specialized.
template <>
void foo(int const&, float&);
Note that while looking for a primary template, the arguments provided (i.e. not to be deduced) are used to check the resulting function parameter of the primary template against the resulting function parameter of the specialization. They have to be equal.
template <typename T, typename U>
void foo(T&, U&) {}
// Error - no matching primary template found.
template <>
void foo<int, int>(float&, int&);
// Dito:
template <>
void foo<int>(int, int&);
It seems that with a function argument, this specification is
superfluous and the compiler deduces it no matter how it's specified
(with the result that equivalent explicit specifications become
unallowed redeclarations).
Yes, that is indeed the case. Consider that if you specify a template argument invalidly that results in an error:
But the meaning seems to imply something more in this case and the
"empty" specialization (<>) is triggered in a somewhat unforeseen
ways. How come?
For a call, the template arguments are deduced first. Then the specialization with those template arguments is called.
If you explicitly specialized a function template for this particular specialization, here that is print2<> which is print2<short>, then that explicit specialization is thus called. In what way is that unforeseen?
Why do I have to have a default template parameter when specializing
print2 with print2<>() but not without it?
Because the compiler cannot deduce the argument. If you provide a default argument he doesn't have to deduce it in the first place.
What special meaning is derived from leaving the template specialization argument empty
Missing arguments are deduced if possible; an empty argument list means that all arguments are to be deduced.
non-existent
That means you're declaring the primary template, not an explicit specialisation.
or with the specialized type
That means you're declaring an explicit specialisation for that type.
the "empty" specialization (<>) is triggered in a somewhat unforeseen ways. How come?
In both cases, the template argument is deduced. In print1, the primary template declares that T is the same type as the function parameter; so it's deduced from the function parameter. In print2, it's declared with a default type of short, so that is used. So your surprise at seeing print2<> when you think it should be print2<short> is explained: print2<> is print2<short>.
Why do I have to have a default template parameter when specializing print2 with print2<>() but not without it?
If there were neither a default argument nor a function parameters from which to deduce an argument, then it would be impossible to deduce a type for the specialisation, so <> couldn't be used. I don't know what you mean by "without it"; if you mean "without <>", then you're declaring the primary template, not a specialisation, and the parameter is generic.

function overload matching template template

I would expect the last two lines of the first code example to print the same.
The types are deducted as I expect and the the overload resolution is also as I expect.
However, if I explicitly type qualify the function call, then I get a different result then when the type is deduced.
The second code example repeats the exercise replacing overload resolution with specialization. In that case everything works as anyone would expect.
Any explanation?
EDIT: I added one more line showing what Karthik was mentioning regarding print<R,int>(r); which I also do not understand.
Code Example 1: (function template overloading)
#include <iostream>
template <typename T>
void print (T i)
{
std::cout << "simple" << std::endl;
}
template <template<typename> class FF, typename TT>
void print (FF<TT> i)
{
std::cout << "template" << std::endl;
}
template <typename T1, typename T2>
void print (T1 a)
{
T2 b;
std::cout << "two type parameters" << std::endl;
}
template <>
void print<int>(int i)
{
std::cout << "int" << std::endl;
}
template <typename T>
struct R
{
T x;
};
int main()
{
R<int> r;
print<int>(1.1); // ok, prints "int"
print(1.1); // ok, prints "simple"
print<int>(1); // ok, prints "int"
print(1); // ok, prints "int"
print(r); // ok, prints "template"
print<int,int>(1); // ok, prints "two type parameters"
print<R<int>,int>(r); // ok, prints "two type parameters"
print<R<int> >(r); // (1) ?? why "simple" ??
print<R,int >(r); // (2) ?? prints "template", why does it compile at all ??
// gcc 4.6.2 (-std=c++0x) and 4.8.1 (-std=c++11)
// clang++ 3.3.1 same behavior as gcc
}
Code Example 2: (class template specialization).
#include <iostream>
template <typename T>
struct P
{
static void print (T i)
{
std::cout << "simple" << std::endl;
}
};
template <template<class TT> class FF, typename TT>
struct P <FF<TT> >
{
static void print (FF<TT> i)
{
std::cout << "template" << std::endl;
}
};
template <>
struct P<int>
{
static void print(int i)
{
std::cout << "int" << std::endl;
}
};
template <typename T>
struct R
{
T x;
};
int main()
{
R<int> r;
P<double>::print(1.1); // ok, prints "simple"
P<int>::print(1); // ok, prints "int"
P<R<int> >::print(r); // ok, prints "template"
//P<R,int >::print(r); // ok, does not compile
}
Well, let's look at what the compiler thinks of each of these.
template <typename T> void print (T i); // (1)
template <template<typename> class FF, typename TT> void print (FF<TT> i); // (2)
template <typename T1, typename T2> void print (T1 a); // (3)
template <> void print<int>(int i); // (4)
Ok, some preliminaries: we have three function templates here that overload each other (1, 2, and 3), and 4 is a specialization of 1.
All three overloads have a single function parameter. In addition, the functions have template parameters:
1 has a single type template parameter that can be deduced from the function parameter.
2 has a template template parameter and a type template parameter, both of which can be deduced from the function parameter.
3 has two type template parameters, only the first of which can be deduced (making the deduction useless).
Now let's look at the calls. When there are explicit template arguments, the compiler will always "pre-filter" the overloads for those functions that can be instantiated that way.
print<int>(1.1); // ok, prints "int"
One explicit type template argument. 1 matches. 2 doesn't match, because the first argument isn't a template. 3 matches, fixing T1 to int; however, T2 cannot be deduced, so it falls away, too. 1 is chosen with the parameter T being int. This matches the specialization 4.
print(1.1); // ok, prints "simple"
No explicit template arguments. Deduction starts; the argument type is double. 1 matches; T is double. 2 requires the pattern FF<TT>, and double doesn't match that, so failure. 3 can deduce T1 to double, but has nothing for T2, so it fails too. 1 is chosen. The specialization doesn't match.
print<int>(1); // ok, prints "int"
This is identical to the first case, except that during final overload resolution, an implicit conversion happens.
print(1); // ok, prints "int"
This is identical to the second case, except that the deduced type is int (still doesn't match FF<TT>), so the specialization matches.
print(r); // ok, prints "template"
Deduction gives the following results: 1 matches, with T = R<int>. For 2, R<int> matches the pattern FF<TT>, so it is viable, with FF = R and TT = int. 3, as usual, doesn't know what to do with T2. Overload resolution gets identical sequences for 1 and 2 (identity), so partial function template ordering resolves the ambiguity: 2 is more specialized than 1 and is chosen.
print<int,int>(1); // ok, prints "two type parameters"
Two explicit type template arguments. 1 only accepts one. 2 wants a template as the first argument. 3 is left.
print<R<int>,int>(r); // ok, prints "two type parameters"
This is identical to the previous case. The first argument is R<int> instead of int, but that's still just a type and 2 doesn't like it.
print<R<int> >(r); // (1) ?? why "simple" ??
This is identical to the first and third cases. We have one explicit type template argument. 3 fails to deduce T2, 2 wants a template as the first argument, so 1 is the only choice. R<int> is a type, not a template.
print<R,int >(r); // (2) ?? prints "template",
Here, we have two explicit template arguments, the first a template, the second a type. 1 only accepts one argument. 3 wants a type for its first template parameter. 2 is happy to take the template for its first and the type for its second parameter.
The key lessons here are:
Explicit template arguments are matched to the template parameters before any deduction or overload resolution happens, so only some functions match in the first place.
1 and 2 are overloads, and overload resolution happens separately for them. It would be different if 2 was a specialization of 1, but partial function template specialization doesn't exist.
It's only a template until you give it arguments. An instantiated function template is a function. An instantiated class template is a class (and thus a type). There is no difference between the instantiation of a class template and a non-template class, except for the pattern matching that argument deduction and partial specialization do.
Edit: To answer the expanded question.
When I replace function overloading with template specialization, then template pattern matching works as I would have expected. I have some trouble believing that the pattern matching rules also differ between classes and functions.
This is a matter of perspective. There are no pattern matching rules for classes and functions, so you can't say that they differ or not. There are pattern matching rules for partial specialization and for template argument deduction. These are actually the same; the section on partial specialization (14.5.5) refers to the section on function template argument deduction (14.8.2).
So the pattern matching rules are the same.
However, argument deduction only applies to functions (there's no argument deduction for class templates, at least not yet), while partial specialization only applies to classes (you can't partially specialize functions). This is the key difference between functions and classses: in your first example, you have two function templates:
template <typename T> void print(T i);
template <template <typename> class FF, typename TT> void print(FF<TT> i);
These are two different templates. They are completely independent. It's up to the complicated rules and interactions of explicit parameter passing, argument deduction, and overload resolution to determine which one is meant in any given invocation. However, and this is important, each can exist without the other. In other words, imagine you had only one function:
template <template <typename> class FF, typename TT> void something_else(FF<TT> i);
Would you then be surprised that something_else<R, int>(r); is valid? You have a template with two parameters, and you pass two arguments. The existence of another template with just one argument doesn't change that!
This is important, so I'll repeat it: Two function templates, even if they have the same name, are completely independent templates.
Not so with classes. If you try the same thing with classes, the compiler will complain:
template <typename T> class Q {};
template <template <typename> class FF, typename TT> class Q {};
Clang says:
redef.cc:2:5: error: too many template parameters in template redeclaration
You cannot have two class templates with the same name. The compiler thinks you want to declare the old Q again, and complains that the template parameter lists don't match.
The only thing you can do with class templates is specialize them, as you did in your second example:
template <typename T> class P {};
template <template <typename> class FF, typename TT> class P<FF<TT>> {};
But note that these are not independent templates. They are not even the same thing. The first is a class template, whereas the second is a class template partial specialization. The second is completely dependent on the first; removing the primary template means the specialization no longer compiles:
redef.cc:2:64: error: explicit specialization of non-template class 'P'
Unlike the overloaded function templates, a class template partial specialization is not an entity the user can reference. For the user, there is one template, P, and it has one template parameter. The specialization will match if this one parameter takes a specific form, but unlike the second function template in the first example, the specialization is not an independent template with two parameters.
This is why P<R<int>>::print(r) compiles and works: P has one parameter, and R<int> is passed for it. The partial specialization matches the pattern and is therefore chosen. But P<R, int>::print(r) does not work: P only has one template parameter, and here you're trying to pass two. The specialization is not its own entity and therefore is not considered.
But the function templates are all independent, full templates. Only the full specialization template <> void print<int>(int i) is not.
So to sum up:
Function templates can be fully specialized or overloaded. Overloaded function templates are fully independent: when you want to know what arguments you can or should explicitly supply, look at all their parameter lists in turn.
Avoid specializing function templates. It interacts with overloaded function templates in weird ways, and you can end up with a function different from what you expected being called. Just overload function templates, with other function templates and plain functions. The partial ordering rules are intuitive; just remember that when in doubt, a plain function is chosen over a template.
Class templates can be fully or partially specialized, but not overloaded. Specializations are not independent templates; when instantiating a class template, you always have to go to the primary template for the parameter list.
The matching rules for choosing a partial specialization and for deducing template arguments from function arguments are the same; however, when you explicitly pass template arguments to a function template, deduction is not performed for these parameters.
This is a guess not an answer, those with the standard at their finger tips can enlighten us all,
But let me take an educated guess
template <template<typename> class FF, typename TT> //......(1)
TT is a type while FF is considered a template template parameter
template <typename T> // .....(2)
T is a type
Now when Explicitly specifying the type, R<int>, it is a concrete type, thus (2) is picked.
When asking it to infer, I guess the compiler tries both options and (1) fits closer (or more specific), and thus that is chosen.
When explicitly specifying <R,int>, ofcourse we use the exact signature of (1) and that is why that one is picked.
+1 to the question, I would not have expected this either.
Perhaps some useful information can be found here
The line print< R<int> >(r); looks like a single-template-parameter print (it can't guess what you want) so it calls the single-template-parameter function with T = R<int>.
print< R,int >(r); calls for a two-template-parameter function, of which there is only one version (template). Luckily R is a template that can be instantiated with int so it compiles.
It would print simple because the type R<int> is deduced as int. In your case, you need to pass 2 parameters to explicitley make it deduce as template <template<typename> class FF, typename TT>

Difference between explicit specialization and regular functions when overloading a template function

I'm on a roll today. Here goes n00b question number 7:
What's the difference between explicit specialization and just regular functions when you try to overload a template function?
What's the appropriate situation to use the explicit specialization? I don't quite understand it:
#include <iostream>
template <typename s> void test(s var1);
template <> void test<int>(int var1);
int main(){
test(1);
test(1.1);
test("hello!!");
return 0;
}
template <typename s> void test(s var1){
std::cout << var1 << std::endl;
}
template <> void test<int>(int var1){
std::cout << "int " << var1 << std::endl;
}
As oppose to:
#include <iostream>
template <typename s> void test(s var1);
void test(int var1);
int main(){
test(1);
test(1.1);
test("hello!!");
return 0;
}
template <typename s> void test(s var1){
std::cout << var1 << std::endl;
}
void test(int var1){
std::cout << "int " << var1 << std::endl;
}
There really isn't a difference between an explicitly specialized template function and a non-template regular function other than the fact that when the compiler looks for a matching signature type for the function call, it will first pick a non-template function that matches the required signature before trying to instantiating any available template functions that may fulfill the required signature match.
If you are going to declare and define a function inside a header file that is not a template-function though, you will have to declare the function as inline. That is because a template function is not an actual function that is linked with a code module until it is actually instantiated. The linker then throws away that instantiation after compiling the code module. If the linker did not do this, then every time a .cpp file included the header file, the linker would complain about duplicate definitions for a function. Using the inline keyword on a non-template function has a similar effect at the compiler level, in that any time the function is used in a .cpp file, the compiler replaces that function call with the body of the function code from the inline function in the header file, and avoids the overhead of a function call with an associated stack active record setup and clean-up. Therefore the linker won't complain about duplicate definitions for a function.
I'm not an expert, but my experience is to use templates (and specialization) when I want to define different return types. You can't overload the return type of a function.
A major difference is: Explicit specializations don't participate in overloading at all.
template<typename T> void f(T const&);
template<> void f<char const*>(char const * const&);
Calling with f("hello") will not consider any explicit specializations. It will only take all templates, and deduce their template arguments. The above T will be deduced to char[6], and so the specialization won't be selected.
If you overload the function template instead, you have completely different characteristics.
template<typename T> void f(T const&);
void f(char const * const&);
Calling this, it will select the second function, because both the (char const(&)[6]) parameter of the generated specialization and the (char const * const&) parameter match the argument equally well, but the second function is a non-template function, hence it is preferred eventually.
When the compiler comes across a function call, it first looks for a non-template function definiton, then an explicitly specialized template and finally, a template definition whose signature matches with the function call.
So, for example, if you have an explicitly defined template and a template, then the complier goes for the explicitly defined template. Therefore, you should use an explicity specialzed template when you want to handle a particular datatype in a different manner from the way the template would have handled it.
Another use for explicit specialization is when you want to "overload" a function that does not take any arguments. You can use explicit specialization to give different definitions to the function to handle different datatypes.
IMHO, explicit specialization for function template should be used when, you are going to call that function using explicit template argument. e.g.
test<int>(myClass); // no argument for 'int' -> declare test() as template specialization
In other cases, you should always use normal specialization. e.g.
test(10, myClass); // argument 10 is 'int' -> test() should be normal specialized
Technically there is no difference between normal and explicit template specialization of a function. The normal specialized versions are completely independent of template functions.