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.
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.
One explicit type template argument. 1 matches. 2 doesn't match, because the first argument isn't a template. 3 matches, fixing
T1
toint
; however,T2
cannot be deduced, so it falls away, too. 1 is chosen with the parameterT
beingint
. This matches the specialization 4.No explicit template arguments. Deduction starts; the argument type is
double
. 1 matches;T
is double. 2 requires the patternFF<TT>
, anddouble
doesn't match that, so failure. 3 can deduceT1
todouble
, but has nothing forT2
, so it fails too. 1 is chosen. The specialization doesn't match.This is identical to the first case, except that during final overload resolution, an implicit conversion happens.
This is identical to the second case, except that the deduced type is
int
(still doesn't matchFF<TT>
), so the specialization matches.Deduction gives the following results: 1 matches, with
T = R<int>
. For 2,R<int>
matches the patternFF<TT>
, so it is viable, withFF = R
andTT = int
. 3, as usual, doesn't know what to do withT2
. 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.Two explicit type template arguments. 1 only accepts one. 2 wants a template as the first argument. 3 is left.
This is identical to the previous case. The first argument is
R<int>
instead ofint
, but that's still just a type and 2 doesn't like it.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.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:
Edit: To answer the expanded question.
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:
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:
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:
Clang says:
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:
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:
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, andR<int>
is passed for it. The partial specialization matches the pattern and is therefore chosen. ButP<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: