ambiguous template instantiation error with gcc - c++

For the code below I get an ambiguous template instantiation error with gcc.
However, using Clang or Visual Studio the Code compiles fine.
A full working example of the code can be found here:
http://coliru.stacked-crooked.com/a/60ef9d73ce95e6f9
I have a class template that is build from an aggegate type
template<template<typename...> typename AggregateType, typename ...>
struct MyClass;
The aggregate type is composed from a list of base classes, for example
template<typename ... Bases>
struct Aggregate : Bases...
{ };
I have defined two specialzations of MyClass. The first specialization is the common case and reads
// specialization for two argument list for the
// aggregate type
template<template<typename...> typename AggregateType,
typename Base,
typename ... Bases1,
typename ... Bases2>
struct MyClass<
AggregateType,
AggregateType<Bases1...>,
AggregateType<Base, Bases2...>>
{
void func()
{
std::cout << "not specialized\n";
}
};
A second specialization handels the case when the the second base list has only 1 argument
// specialization for the second argument list with length 1
template<template<typename...> typename AggregateType,
typename Base,
typename ... Bases1>
struct MyClass<
AggregateType,
AggregateType<Bases1...>,
AggregateType<Base>>
{
void func()
{
std::cout << "specialized\n";
}
};
Using MyClass with a second argument list of length 1, I expected the compiler to choose the second specialization of MyClass, since it is the more specilized template
class Foo {};
class Bar {};
int main()
{
// this should give the not specialized class
using NotSpecialized = MyClass<Aggregate, Aggregate<Foo, Bar>, Aggregate<Foo, Bar>>;
NotSpecialized ns;
ns.func();
// this should give the specialized class
using Specialized = MyClass<Aggregate, Aggregate<Foo, Bar>, Aggregate<Foo>>;
Specialized s;
s.func();
}
While the code works fine with Clang, gcc gives an ambiguous template instantiation error. How can I circumvent this error and still use gcc?
If I remove the AggregateType template argument, the code also works with gcc, see http://coliru.stacked-crooked.com/a/c1f6edd5fab7df4d

(All ISO Standard references below refer to N4659: March 2017 post-Kona working draft/C++17 DIS, and all example program results are consistent over GCC and Clang for C++11, C++14 and C++17)
I believe GCC is wrong here, but I haven't been able to find a corresponding (open) GCC bug report.
[temp.class.order]/1 covers the partial ordering of class template specializations [emphasis mine]:
For two class template partial specializations, the first is more
specialized than the second if, given the following rewrite to two
function templates, the first function template is more specialized
than the second according to the ordering rules for function
templates:
(1.1) Each of the two function templates has the same template parameters as the corresponding partial specialization.
(1.2) Each function template has a single function parameter whose type is a class template specialization where the template arguments
are the corresponding template parameters from the function template
for each template argument in the template-argument-list of the
simple-template-id of the partial specialization.
Thus, for analyzing ordering, we re-write the class template specializations as function templates, as per above:
// G)
template<template<typename...> typename AggregateType,
typename Base,
typename... Bases1,
typename... Bases2>
void f(MyClass<AggregateType,
AggregateType<Bases1...>,
AggregateType<Base, Bases2...>>);
// F)
template<template<typename...> typename AggregateType,
typename Base,
typename... Bases1>
void f(MyClass<AggregateType, AggregateType<Bases1...>, AggregateType<Base>>);
The partial ordering of the G and F overloads of f is governed by [temp.func.order]/2, [temp.func.order]/3 and [temp.func.order]/4 [emphasis mine]:
[temp.func.order]/2
Partial ordering selects which of two function templates is more
specialized than the other by transforming each template in turn
(see next paragraph) and performing template argument deduction
using the function type. The deduction process determines whether
one of the templates is more specialized than the other. If so, the
more specialized template is the one chosen by the partial ordering
process.
[temp.func.order]/3
To produce the transformed template, for each type, non-type, or
template template parameter (including template parameter packs
thereof) synthesize a unique type, value, or class template
respectively and substitute it for each occurrence of that parameter
in the function type of the template. [...]
[temp.func.order]/4
Using the transformed function template's function type, perform type deduction against the other template as described in [temp.deduct.partial]. [...]
Thus, to produce the transformed template for the two f overloads above, specifically considering the template template parameter AggregateType (as used in both overloads) and the instantiation of these overloads with the particular class template Aggregate and classes Foo and Bar,
template<typename ... Bases>
struct Aggregate : Bases...
{ };
class Foo {};
class Bar {};
used as arguments for the template template parameter and template parameters, respectively, we may without loss of generality consider the following (partially) transformed function templates as argument templates when continuing the analysis of the partial ordering of the original class templates:
// G-transformed (argument template>
template<typename... Bases2>
void f(MyClass<Aggregate, Aggregate<Foo, Bar>, Aggregate<Foo, Bases2...>>);
// F-transformed (argument template>
void f(MyClass<Aggregate, Aggregate<Foo, Bar>, Aggregate<Foo>>);
From [temp.deduct.partial]/2, [temp.deduct.partial]/10 and [temp.deduct.partial]/11 [extracts, emphasis mine]:
[temp.deduct.partial]/2
Two sets of types are used to determine the partial ordering. For each
of the templates involved there is the original function type and the
transformed function type. [...] The deduction process uses the
transformed type as the argument template and the original type of
the other template as the parameter template.
[temp.deduct.partial]/10
Function template F is at least as specialized as function template G if, for each pair of types used to determine the ordering, the type from F is at least as specialized as the type from G. F is more specialized than G if F is at least as specialized as G and G is not at least as specialized as F.
[temp.deduct.partial]/11
If, after considering the above, function template F is at least as specialized as function template G and vice-versa, and if G has a trailing parameter pack for which F does not have a corresponding parameter, and if F does not have a trailing parameter pack, then F is more specialized than G.
it follows that that F is at least as specialized as G (/10), and moreover that F is more specialized than G due to the (additional) trailing parameter pack Bases2 that is present in G but not in F (/11). It may even be possible to directly apply the second part of [temp.deduct.partial]/10 to argue that F is more specialized than G as Aggregate<Foo> is more specialized than Aggregate<Foo, Bases2...>>.
Either way, either per /10 and /11, or per /10 alone, the Specialized alias
using Specialized = MyClass<Aggregate, Aggregate<Foo, Bar>, Aggregate<Foo>>;
refers non-ambigiously to the "second specialization" (from OPs post) of MyClass, specifically the specialization that was re-written to the F function template above, as this class template specialization is more specialized than the "first specialization" (the one with the additional Bases2 variadic template parameter pack).

Related

How do variadic type template parameters and non-type template parameters of the template template parameter of a nested class constrain each other?

Consider the following structure: S is a class template with a variadic pack of template type parameters ...Ts. The class contains a nested class template N, which has a single template template parameter C. C itself is templated with a variadic pack of non-type template parameters that have exactly the types Ts....
template <typename ...Ts>
struct S
{
template <template <Ts...> typename C>
struct N
{
C<42> c;
};
};
GCC rejects the declaration of c with:
error: expansion pattern '<anonymous>' contains no parameter packs
C<42> c;
^
I don't know what this diagnostic means, and I'm guessing this is a GCC bug.
Clang accepts this structure, and also accepts a reasonable instantiation such as:
template<int> struct W {};
S<int>::N<W> w; // ok, makes sense
Of course, the declaration C<42> c; itself places constraints on the template used as an argument for the parameter C, which will be required even if the Ts... in C were simply auto.... e.g. the first argument of Ts... must be a type that is implicitly convertible from an int. Also, the remaining parameters in Ts..., if any, must have defaults.
template<bool(*)()> struct X1 {};
S<int>::N<X1> x1; // error: value of type 'int' is not implicitly convertible to 'bool (*)()'
template<int, char> struct X2 {};
S<int>::N<X2> x2; // error: too few template arguments for class template 'X2'
Interestingly, there do appear to be constraints imposed by the relationship between ...Ts and Ts.... e.g. all the specified arguments for S must now be valid non-type template parameter types:
template<int> struct Y {};
S<int, void>::N<Y> y; // error: a non-type template parameter cannot have type 'void'
On the other hand, Clang also accepts instantiations with seemingly incompatible arguments for S, and non-type template parameters for C:
template<int> struct Z {};
S<bool(*)(), bool>::N<Z> z; // ok ?? But why? both number and type of 'Ts' is different
Here's a demo.
So what are the rules for how ...Ts and Ts... constrain each other in this structure?
I came across this issue while trying to understand this question where it's indicated that MSVC doesn't accept the code as well.
For your primary question (nested class with non-type template arguments dependent on template arguments in outer class) this is a bug in GCC, #86883 (See comment #3)
I think Clang is not right.
temp.param#15
A template parameter pack that is a parameter-declaration whose type contains one or more unexpanded parameter packs is a pack expansion.
For the template template parameter of nested template class N, that is template <Ts...> typename C, where Ts... is a pack instantiation, which has the following rule:
Each Ei is generated by instantiating the pattern and replacing each pack expansion parameter with its ith element. Such an element, in the context of the instantiation, is interpreted as follows:
if the pack is a template parameter pack, the element is a template parameter of the corresponding kind (type or non-type) designating the type or value from the template argument;
So, for this example S<bool(*)(), bool>::N<Z> z; , instantiate Ts... would give a list bool(*)(), bool. Hence, the question can be simplified to:
template<template<bool(*)(), bool> class C>
struct Nested{};
template<int> struct Z {};
int main(){
Nested<Z> z; // is well-formed?
}
Per temp.arg.template#3
A template-argument matches a template template-parameter P when P is at least as specialized as the template-argument A.
Does the argument Z match the parameter C? According to this rule temp.arg.template#4
A template template-parameter P is at least as specialized as a template template-argument A if, given the following rewrite to two function templates, the function template corresponding to P is at least as specialized as the function template corresponding to A according to the partial ordering rules for function templates. Given an invented class template X with the template parameter list of A (including default arguments):
Each of the two function templates has the same template parameters, respectively, as P or A.
Each function template has a single function parameter whose type is a specialization of X with template arguments corresponding to the template parameters from the respective function template where, for each template parameter PP in the template parameter list of the function template, a corresponding template argument AA is formed. If PP declares a parameter pack, then AA is the pack expansion PP... ([temp.variadic]); otherwise, AA is the id-expression PP.
If the rewrite produces an invalid type, then P is not at least as specialized as A.
That means, we have an invented template class X has the form:
template<int>
struct InventedX{};
Then, the rewritten function template for A has the form:
template<int N>
auto iventend_function(X<N>);
while the rewritten function template for P has the form:
template<bool(*A)(), bool B>
auto invented_function(X<A,B>) // invalid type for X<A,B>
So, P is not at least as specialized as A. Hence A cannot match with P. So, S<bool(*)(), bool>::N<Z> z; shall be ill-formed.

gcc vs. clang, msvc and icc: Is this function call ambiguous?

All compilers I could get my hands on agree that this is fine:
template <typename Check, typename... T>
auto foo(Check, T...) -> void;
template <typename... T>
auto foo(int, T...) -> void;
int main()
{
foo(7, "");
}
However, the following code (with a leading template parameter that cannot be deduced from the function parameters) is ambiguous according to gcc:
template <typename X, typename Check, typename... T>
auto bar(Check, T...) -> void;
template <typename X, typename... T>
auto bar(int, T...) -> void;
int main()
{
bar<void>(7, ""); // ambiguous according to gcc
bar<void>(7); // just fine
}
On the other hand, clang, msvc and icc are quite happy with this.
Which compiler is right?
References to the respective sections of the standard preferred.
This is core issue 200.
The description of how the partial ordering of template functions is
determined in 14.5.6.2 [temp.func.order] paragraphs 3-5 does not make
any provision for nondeduced template parameters. For example, the
function call in the following code is ambiguous, even though one
template is "obviously" more specialized than the other:
template <class T> T f(int);
template <class T, class U> T f(U);
void g() {
f<int>(1);
}
The reason is that neither function parameter list allows template parameter T to be deduced; both deductions fail, so neither
template is considered more specialized than the other and the
function call is ambiguous.
The resolution of core issue 214, which this one was reduced to, introduced [temp.deduct.partial]/11:
In most cases, all template parameters must have values in order for deduction to succeed, but for partial ordering purposes a template parameter may remain without a value provided it is not used in the types being used for partial ordering.
Apparently GCC's implementation of this wording is buggy once packs come into play.
IMHO I believe that GCC is wrong and CLANG is correct here. I'll try to justify my claim below:
According to the standard §14.8.3/p1 Overload resolution [temp.over] (Emphasis Mine):
A function template can be overloaded either by (non-template)
functions of its name or by (other) function templates of the same
name. When a call to that name is written (explicitly, or implicitly
using the operator notation), template argument deduction (14.8.2)
and checking of any explicit template arguments (14.3) are performed
for each function template to find the template argument values (if
any) that can be used with that function template to instantiate a
function template specialisation that can be invoked with the call
arguments. For each function template, if the argument deduction and
checking succeeds, the template-arguments (deduced and/or explicit)
are used to synthesise the declaration of a single function template
specialisation which is added to the candidate functions set to be
used in overload resolution. If, for a given function template,
argument deduction fails or the synthesised function template
specialisation would be ill-formed, no such function is added to the
set of candidate functions for that template. The complete set of
candidate functions includes all the synthesised declarations and all
of the non-template overloaded functions of the same name. The
synthesised declarations are treated like any other functions in the
remainder of overload resolution, except as explicitly noted in
13.3.3.144
[Example:
template<class T> T max(T a, T b) { return a>b?a:b; }
void f(int a, int b, char c, char d) {
int m1 = max(a,b); // max(int a, int b)
char m2 = max(c,d); // max(char a, char b)
int m3 = max(a,c); // error: cannot generate max(int,char)
}
144) The parameters of function template specializations contain
no template parameter types. The set of conversions allowed on deduced
arguments is limited, because the argument deduction process produces
function templates with parameters that either match the call
arguments exactly or differ only in ways that can be bridged by the
allowed limited conversions. Non-deduced arguments allow the full
range of conversions. Note also that 13.3.3 specifies that a
non-template function will be given preference over a template
specialisation if the two functions are otherwise equally good
candidates for an overload match.
From the above we get that explicit template arguments will be checked and if checking succeeds then will be used to synthesise a specialisation that will be added to the candidate functions for overload resolution. Thus, the fact the you specify explicitly X is irrelevant for the process.
Also from the C++ standard §13.3.3/p1.7 Best viable function [over.match.best]:
F1 and F2 are function template specialisations, and the function
template for F1 is more specialised than the template for F2
according to the partial ordering rules described in 14.5.6.2.
Now from §14.5.6.2/p3 Partial ordering of function templates [temp.func.order] we get that in partial ordering parameters packs are also into play, so no problem also here.
Now:
template <typename X, typename... T>
auto bar(int, T...) -> void;
is more specialized than:
template <typename X, typename Check, typename... T>
auto bar(Check, T...) -> void;
Therefore calling:
bar<void>(7, "");
is not ambiguous.
Based on the above I believe that this is a GCC bug.

Why is initialization of a constant dependent type in a template parameter list disallowed by the standard?

In the answer to this post "(Partially) specializing a non-type template parameter of dependent type", it states:
The type of a template parameter corresponding to a specialized
non-type argument shall not be dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
My question is why is this restriction here? There is at least one use case where I find that this restriction interferes with writing clean code. E.g.
template <typename T, T*>
struct test;
template <typename T>
struct test<T, nullptr> // or struct test<T, (T*)nullptr>
{
};
template <typename R, typename...ARGs, R(*fn)(ARGs...)>
struct test<R(ARGs...), fn>
{
};
Though I'm unsure if there are other cases that stating a constant based on a type is a problem beyond not making any sense.
Anyone have a reason for why this is so?
(IMHO) The most common reasons the standard disallows a specific feature are:
The feature is covered by another mechanism in the language, rendering it superfluous.
It contradicts existing language logic and implementation, making its implementation potentially code breaking.
Legacy: the feature was left out in the first place and now we've built a lot without it that it's almost forgotten (see partial function template specialization).
Difficulty of implementation is rarely a factor, though it may take some time for compiler implementations to catch up with evolution on the "hard" stuff.
You could always wrap your non type template parameter in another type:
template < typename T1, typename T2 >
struct Demo {}; // primary template
template < typename T >
struct Demo<T, integral_constant<T, 0>> {}; // specialization
I doubt this hack falls into case 1. Case 3 is always a possibility so lets examine case 2. To do this, we have to know which are the related rules the standard imposes on class templates partial specializations.
14.5.5 Class template partial specializations
A non-type argument is non-specialized if it is the name of a non-type parameter. All other non-type arguments are specialized. (C1)
Within the argument list of a class template partial specialization, the following restrictions apply:
A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier. (C2)
The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization. (C3)
I marked the first three Clauses I found relevant (the third is the one in question). According to C1 in our case we have a specialized non-type argument so C2 should stand, yet this
template <class T, T t> struct C {};
template <class T> struct C<T, 1>;
is actually
template <class T, T t> struct C {};
template <class T> struct C<T, T(1)>; // notice the value initialization
so the partially specialized non type argument T t involves the template parameter of the partial specialization class T in an expression other than an identifier; furthermore such specializations are bound to involve class T in a value initialization which will always be a violation of the rules. Then C3 comes along and clears that out for us so that we won't have to make that deduction every time.
So far we've established that the rules are in sync with themselves but this does NOT prove case 2 (once we remove the initial limitation every other related limitation falls apart). We'd have to dive into matching class template partial specializations rules; partial ordering is considered out of scope here because if we can produce valid candidates it's up to the programmer to put together a well formed program (i.e. not create ambiguous uses of class templates).
Section
Matching of class template partial specializations [temp.class.spec.match]
describes the (give or take) "pattern matching" process involved in template specialization. Rule 1 is the overall workflow of the procedure and the subsequent rules are those that define correctness
A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list
A non-type template argument can also be deduced from the value of an actual template argument of a non-type parameter of the primary template.
In a type name that refers to a class template specialization, (e.g., A) the argument list shall match the template parameter list of the primary template. The template arguments of a specialization are deduced from the arguments of the primary template.
These rules are not violated by allowing the type of a template parameter corresponding to a specialized non-type argument to be dependent on a parameter of the specialization. So IMHO there is no specific reason why we can't have this feature in future revisions of the language: legacy is to blame. Sadly I didn't manage to find any language proposals with the initiative to introduce this feature.

How can I deduce the type and its template arguments for a meta-function?

Suppose I have a meta-function which requires both the type and its arguments. How can I do this without forcing the user of the function to provide both the type and its arguments separately?
using MyType = SomeType<T1, T2, T3>; // This is the type to pass to the functor
template <typename MyType, typename ... Args>
struct MetaFunction
{
using type = SomeOperation<MyType, Args...>;
}
// I want to be able to call my functor like this:
MetaFunction<MyType>::type;
// but with the above I have to call it like this:
MetaFunction<MyType, T1, T2, T3>::type;
How can I do this?
You can "disassemble" a class template specialization into the template itself and the template parameters by using partial spezialiation (some form of pattern-matching).
First, we define MetaFunction to be a (class) template that takes a type as its only parameter:
template <typename T>
struct MetaFunction;
Then, we define a partial specialization of this class template MetaFunction. A partial specialization is a special case of a class template. If the case applies, the partial specialization is used instead of the original (primary) template to make a class. The template "interface", i.e. the amount and kind of template arguments you can/must provide to instantiate the MetaFunction template is not changed by the existence of specializations.
A partial specialization, as opposed to an explicit specialization, is also a template, which implies that it has template parameters. The partial means that it does not specify fully for which types (sets of template arguments) it applies as a special case. Typically, partial specializations apply to subsets of the set of possible/valid arguments you can supply to the primary template.
template <template<typename...> class TT, typename ... Args>
struct MetaFunction /* not finished yet */
There are three kinds of template parameters:
Type parameters
"Value" parameters (non-type)
Template parameters
This partial specialization uses a template template-parameter. A valid argument for such a parameter must be a either a class template or an alias template.
We specify when this partial specialization shall be used by providing a "pattern":
template <template<typename...> class TT, typename ... Args>
struct MetaFunction<TT<Args...>>
{
using type = SomeOperation<TT, Args...>;
};
This partial specialization will be used if the type supplied to the MetaFunction template matches the pattern TT<Args...>, i.e., if it can be disassembled into a class/alias(*) template TT and some template type parameters Args.
(*) As T.C. correctly noted, a type produced via an alias-template is not associated with the alias-template. Therefore, you cannot deduce an alias-template from a type.

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>