Reading the C++11 standard I can't fully understand the meaning of the following statement. Example are very welcome.
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. [Note: The creation of the transformed type
is described in 14.5.6.2. — end note ] The deduction process uses the
transformed type as the argument template and the original type of the
other template as the parameter template. This process is done twice
for each type involved in the partial ordering comparison: once using
the transformed template-1 as the argument template and template-2 as
the parameter template and again using the transformed template-2 as
the argument template and template-1 as the parameter template
-- N3242 14.8.2.4.2
While Xeo gave a pretty good description in the comments, I will try to give a step-by-step explanation with a working example.
First of all, the first sentence from the paragraph you quoted says:
For each of the templates involved there is the original function type and the transformed function type. [...]
Hold on, what is this "transformed function type"? Paragraph 14.5.6.2/3 explains that:
To produce the transformed template, for each type, non-type, or template template parameter (including
template parameter packs (14.5.3) 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 [...]
This formal description may sound obscure, but it is actually very simple in practice. Let's take this function template as an example:
template<typename T, typename U>
void foo(T, U) // #1
Now since T and U are type parameters, the above paragraph is asking us to pick a corresponding type argument for T (whatever) and substitute it everywhere in the function signature where T appears, then to do the same for U.
Now "synthesizing a unique type" means that you have to pick a fictitious type you haven't used anywhere else, and we could call that P1 (and then pick a P2 for U), but that would make our discussion uselessly formal.
Let's just simplify things and pick int for T and bool for U - we're not using those types anywhere else, so for our purposes, they are just as good as P1 and P2.
So after the transformation, we have:
void foo(int, bool) // #1b
This is the transformed function type for our original foo() function template.
So let's continue interpreting the paragraph you quoted. The second sentence says:
The deduction process uses the transformed type as the argument template and the original type of the other template as the parameter template. [...]
Wait, what "other template"? We only have one overload of foo() so far. Right, but for the purpose of establishing an ordering between function templates, we need at least two of them, so we'd better create a second one. Let's use:
template<typename T>
void foo(T const*, X<T>) // #2
Where X is some class template of ours.
Now what with this second function template? Ah, yes, we need to do the same we previously did for the first overload of foo() and transform it: so again, let's pick some type argument for T and replace T everywhere. I'll pick char this time (we aren't using it anywhere else in this example, so that's as good as some fictitious P3):
void foo(char const*, X<char>) #2b
Great, now he have two function templates and the corresponding transformed function types. So how to determine whether #1 is more specialized than #2 or vice versa?
What we know from the above sentence is that the original templates and their transformed function types must be matched somehow. But how? That's what the third sentence explains:
This process is done twice for each type involved in the partial ordering comparison: once using the transformed template-1 as the argument template and template-2 as the parameter template and again using the transformed template-2 as the argument template and template-1 as the parameter template
So basically the transformed function type of the first template (#1b) is to be matched against the function type of the original second template (#2). And of course the other way round, the transformed function type of the second second template (#2b) is to be matched against the function type of the original first template (#1).
If matching will succeed in one direction but not in the other, then we will know that one of the templates is more specialized than the other. Otherwise, neither is more specialized.
Let's start. First of all, we will have to match:
void foo(int, bool) // #1b
Against:
template<typename T>
void foo(T const*, X<T>) // #2
Is there a way we can perform type deduction on T so that T const* becomes exactly int and X<T> becomes exactly bool? (actually, an exact match is not necessary, but there are really few exceptions to this rule and they are not relevant for the purpose of illustrating the partial ordering mechanism, so we'll ignore them).
Hardly. So let's try matching the other way round. We should match:
void foo(char const*, X<char>) // #2b
Against:
template<typename T, typename U>
void foo(T, U) // #1
Can we deduce T and U here to produce an exact match for char const* and X<char>, respectively? Sure! It's trivial. We just pick T = char const* and U = X<char>.
So we found out that the transformed function type of our first overload of foo() (#1b) cannot be matched against the original function template of our second overload of foo() (#2); on the other hand, the transformed function type of the second overload (#2b) can be matched against the original function template of the first overload (#1).
Conclusion? The second overload of foo() is more specialized than the first one.
To pick a counter-example, consider these two function templates:
template<typename T, typename U>
void bar(X<T>, U)
template<typename T, typename U>
void bar(U, T const*)
Which overload is more specialized than the other? I won't go through the whole procedure again, but you can do it, and that should convince you that a match cannot be produced in either direction, since the first overload is more specialized than the second one for what concerns the first parameter, but the second one is more specialized than the first one for what concerns the second parameter.
Conclusion? Neither function template is more specialized than the other.
Now in this explanation I have ignored a lot of details, exceptions to the rules, and cryptic passages in the Standard, but the mechanism outlined in the paragraph you quoted is indeed this one.
Also notice, that the same mechanism outlined above is used to establish a "more-specialized-than" ordering between partial specializations of a class template by first creating an associated, fictitious function template for each specialization, and then ordering those function templates through the algorithm described in this answer.
This is specified by paragraph 14.5.5.2/1 of the C++11 Standard:
For two class template partial specializations, the first is at least as specialized as the second if, given the
following rewrite to two function templates, the first function template is at least as specialized as the second
according to the ordering rules for function templates (14.5.6.2):
— the first function template has the same template parameters as the first partial specialization and has
a single function parameter whose type is a class template specialization with the template arguments
of the first partial specialization, and
— the second function template has the same template parameters as the second partial specialization
and has a single function parameter whose type is a class template specialization with the template
arguments of the second partial specialization.
Hope this helped.
Related
While creating this answer for another question I came around the following issue. Consider this program (godbolt):
#include <variant>
#include <iostream>
template <typename T>
struct TypeChecker {
void operator()() {
std::cout << "I am other type\n";
}
};
template<typename... Ts, template<typename...> typename V>
requires std::same_as<V<Ts...>, std::variant<Ts...>>
struct TypeChecker<V<Ts...>>
{
void operator()()
{
std::cout << "I am std::variant\n";
}
};
int main()
{
TypeChecker<std::variant<int, float>>{}();
TypeChecker<int>{}();
}
The output (which is also expected) is the following (with clang 14.0.0 as well as with gcc 12.1):
I am std::variant
I am other type
If however the three dots in the parameter list of the template template are removed, like this (whole program live on godbolt):
template<typename... Ts, template<typename> typename V>
,then the output is different for clang and gcc. The clang 14.0.0 compiled program outputs
I am other type
I am other type
whereas the gcc 12.1 compiled program outputs
I am std::variant
I am other type
It seems that using the non-variadic template template exhibits different matching rules in clang and gcc. So my question is, which behavior is correct if it is even well defined, and why?
Since defect report resolution P0522R0 was adopted, exact matching of template parameter lists for template template parameter match is no longer needed, and correct output according to the standard is:
I am std::variant
I am other type
In the current draft (which also contains changes related to C++20 concepts) relevant standard excerpts are temp.arg.template#3-4 (bold emphasis mine):
A template-argument matches a template template-parameter P when P is at least as specialized as the template-argument A. In this comparison, if P is unconstrained, the constraints on A are not considered. If P contains a template parameter pack, then A also matches P if each of A's template parameters matches the corresponding template parameter in the template-head of P. Two template parameters match if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are equivalent ([temp.over.link]), and for template template-parameters, each of their corresponding template-parameters matches, recursively. When P's template-head contains a template parameter pack ([temp.variadic]), the template parameter pack will match zero or more template parameters or template parameter packs in the template-head of A with the same type and form as the template parameter pack in P (ignoring whether those template parameters are template parameter packs).
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-head of A (including default arguments and requires-clause, if any):
(4.1) Each of the two function templates has the same template parameters and requires-clause (if any), respectively, as P or A.
(4.2) 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-head of the function template, a corresponding template argument AA is formed. If PP declares a template 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.
So, as we see, exact (up to special rules for parameter pack) parameter matching is now considered only in the case parameter list of template template parameter contains a pack (like your original example), otherwise only the new at least as specialized as relation is used to test matching, which defines for both template template parameter and argument respective function templates and tests whether parameter-induced function is at least as specialized as argument-induced function according to partial ordering rules for template functions.
In particular, matching A=std::variant to P=template<typename> typename V we get these corresponding function templates:
template<typename...> class X;
template<typename T> void f(X<T>); // for P
template<typename... Ts> void f(X<Ts...>); // for A
So, to prove A matches P, we need to prove f(X<T>) is at least as specialized as f(X<Ts...>). temp.func.order#2-4 says:
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. If both deductions succeed, the partial ordering selects the more constrained template (if one exists) as determined below.
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. ...
Using the transformed function template's function type, perform type deduction against the other template as described in [temp.deduct.partial].
Transformed template of f(X<T>) is f(X<U1>) and of f(X<Ts...>) is f(X<U2FromPack>), where U1 and U2FromPack are two synthesized unique types. Now, temp.deduct.partial#2-4,8,10 says:
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.
[Note 1: The creation of the transformed type is described in [temp.func.order]. — end note]
The deduction process uses the transformed type as the argument template and the original type of the other template as the parameter template. This process is done twice for each type involved in the partial ordering comparison: once using the transformed template-1 as the argument template and template-2 as the parameter template and again using the transformed template-2 as the argument template and template-1 as the parameter template.
The types used to determine the ordering depend on the context in which the partial ordering is done:
(3.1) In the context of a function call, the types used are those function parameter types for which the function call has arguments.130
(3.2) In the context of a call to a conversion function, the return types of the conversion function templates are used.
(3.3) In other contexts the function template's function type is used.
Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types of P and A.
Using the resulting types P and A, the deduction is then done as described in [temp.deduct.type]. ... If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template.
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.
Now, in our case, per 3.3, the function type itself is the only one considered among types to determine ordering. So, per 2, 8 and 10, to know whether f(X<T>) is at least as specialized as f(X<Ts...>) we need to see whether void(X<T>) is at least as specialized as void(X<Ts...>), or, equivalently, whether deduction from type for P=void(X<Ts...>) from A=void(X<U1>) succeeds. It does according to temp.deduct.type#9-10:
If P has a form that contains <T> or <i>, then each argument Pi
of the respective template argument list of P is compared with the corresponding argument Ai of the corresponding template argument list of A. If the template argument list of P contains a pack expansion that is not the last template argument, the entire template argument list is a non-deduced context. If Pi is a pack expansion, then the pattern of Pi is compared with each remaining argument in the template argument list of A. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by Pi. ...
Similarly, if P has a form that contains (T), then each parameter type Pi of the respective parameter-type-list ([dcl.fct]) of P is compared with the corresponding parameter type Ai of the corresponding parameter-type-list of A. ...
Here, per 10, comparison of functions types results in a single comparison of X<Ts...> and X<U1>, which, according to 9, succeeds.
Thus, deduction is succesful, so f(X<T>) is indeed at least as specialized as f(X<Ts...>), so std::variant matches template<typename> typename V. Intuitively, we gave 'more general' template template argument which should work nicely for intended usage of a more specific template template parameter.
In practice, different compilers enable P0522R0 changes under different circumstances, and cppreference template parameters page (section Template template arguments) contains links and information on GCC, Cland and MSVC. In particular, GCC in C++17+ mode enables it by default (and for previous standards with compiler flag fnew-ttp-matching), but Clang doesn't in any mode unless -frelaxed-template-template-args flag is provided, thus you got the difference in output for them. With the flag, Clang also produces correct behaviour (godbolt).
Recently I reported a msvc bug involving a function parameter pack. Also as it turns out here that msvc is actually standard compliant there.
Then when I modified the example to what is shown below I noticed that the modified code also cannot be compiled in msvc but can be compiled in clang and gcc. The code is as follows: Demo link
template<typename T> struct C{};
template<typename T> void f(C<T>)
{
}
template<typename... T> void f(C<T...>)
{
}
int main()
{
f(C<int>{}); //Should this call succeed?
}
Note that in the above example we have as the function parameter C<T...> as opposed to just T.... Now, in the above shown example, I am not 100% sure that if it is a msvc issue or the standard disallows the program.
So my question is, is the above shown code example well formed. That is, should the call f(C<int>{}); succeed choosing the first overload void f(C<T>) instead of void f(C<T...>)?
In other words, which compiler is right here.
So my question is, is the above shown code example well formed.
The code is well-formed as the function template overload with a non-variadic template parameter is more specialized than the overload with a variadic template parameter, by partial ordering rules.
MSVC is incorrect to reject it.
[temp.func.order]/1 through /4 tells us that we need to turn to partial ordering
/1 If a function template is overloaded, the use of a function template
specialization might be ambiguous [...]. Partial ordering of overloaded function template declarations is used in the following contexts to select the function template to which a function template specialization refers:
/1.1 during overload resolution for a call to a function template specialization ([over.match.best]);
[...]
/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. [...] If so, the more specialized template is the one chosen by the partial ordering process. If both deductions succeed, the partial ordering selects the more constrained template (if one exists) as determined below.
/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.
/4 Using the transformed function template's function type, perform type deduction against the other template as described in [temp.deduct.partial].
[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. [...]
/4 Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types of
P and A.
/8 Using the resulting types P and A, the deduction is then done as described in [temp.deduct.type]. [...] If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template.
results in, for the original single function parameter function templates, the following P/A pairs:
P A
-------- ----------
#1: C<T> C<Unique1...>
#2: C<T...> C<Unique2>
Typically, when not in the context of partial ordering, deduction would succeed for both these pairs. However, [temp.deduct.type]/9 has a special case for when the deduction is performed as part of partial ordering:
/9 [...] During partial ordering, if Ai was originally a pack expansion:
/9.2 otherwise, if Pi is not a pack expansion, template argument deduction fails.
This clause means deduction of #1 above (C<T> from C<Unique1...>) fails, whereas #2 (C<T...> from C<Unique2>) succeeds and C<Unique2> is considered at least as specialized as C<T...>. As per [temp.deduct.partial]/10 the non-variadic function template overload is thus at least as specialized as the variadic template function overload and, in the absense of the vice-versa relationsship, moreover more specialized:
/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.
This leads us back to [temp.func.order]/2 and the more specialized function template is chosen by partial ordering:
/2 [...] 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.
Which is also covered by [over.match.best]/2.5
/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
[...]
/2.5 F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2
according to the partial ordering rules described in
[temp.func.order], or, if not that, [...]
Consider this example
struct A { };
template<class T> struct B {
template<class R> int operator*(R&); // #1
};
template<class T, class R> int operator*(T&, R&); // #2
The partial ordering will apply to #1 and #2 to select the best viable function template.
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. This process is done twice for each type involved in the partial ordering comparison: once using the transformed template-1 as the argument template and template-2 as the parameter template and again using the transformed template-2 as the argument template and template-1 as the parameter template.
Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph)
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. [ Note: The type replacing the placeholder in the type of the value synthesized for a non-type template parameter is also a unique synthesized type. — end note ] If only one of the function templates M is a non-static member of some class A, M is considered to have a new first parameter inserted in its function parameter list. Given cv as the cv-qualifiers of M (if any), the new parameter is of type “rvalue reference to cv A” if the optional ref-qualifier of M is && or if M has no ref-qualifier and the first parameter of the other template has rvalue reference type. Otherwise, the new parameter is of type “lvalue reference to cv A”.
So, the original type for #2 is int operator*(T&, R&) and its transformed type is int operator*(UniqueA&, UniqueB&), there's no doubt to the original type of #2. However, I don't know what's the original type for #1(member function template).
The structure of that rule seems that the emphasized part in the above rule should be considered as a step of producing the transformed template.
So, whether the original type of #1 is int operator*(B<T>&, R&) or int operator*(R&). If it's the latter, that wouldn't consistent with common sense. Since int operator*(R&) and int operator*(T&, R&) do not match the number of parameters, how to compare them (A against P)?
How to read the rule for producing the transformed template correctly? If the emphasized part is not considered as a step of the transformation, instead it's a general rule for member function during the partial ordering, Does the rule make it misleading to place such a rule after the process of the transformation?
Yes, it's a bit of a mess. As you've observed, it doesn't make sense for the "original type" of a class non-static member function to lack the inserted this parameter.
The only way to make it work is for the subsequent paragraphs in subclause 3 to apply to the "original" function type on the other side of [temp.deduct.partial] as well as the "transformed" function type. You could just about read it that way for what is presently the first sentence of the second paragraph, reading "each" as applying to both the transformed and original function type:
Each function template M that is a member function is considered to have a new first parameter of type X(M) [...]
However, since the resolution to CWG 2445 in P2108 we have another sentence:
If exactly one of the function templates was considered [...] via a rewritten candidate with a reversed order of parameters, then the order of the function parameters in its transformed template is reversed.
So we quite clearly have this reversal applying asymmetrically, giving an absurd result. On the upside, it's fairly clear how it should read; the adjustments to function type (this insertion and parameter reversal) should apply prior to unique type synthesis/substitution, and apply to the "original" and transformed function type equally.
As far as I can tell, this defect does not appear to have been reported to the Core Language Working Group; it does not appear in the C++ Standard Core Language Active Issues list.
template<typename T>
struct Test{};
template<typename T>
struct Test<T&&>{};
Consider the above example, the standard says that the class template partial specialization shall be more specialized than its primary class template.
Within the argument list of a class template partial specialization, the following restrictions apply:
The specialization shall be more specialized than the primary template.
To determine which is more specialized, the following rules will be applied to them:
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:
Each of the two function templates has the same template parameters as the corresponding partial specialization.
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.
For primary class template, the rewritten function template would be like this:
template<typename T>
void ordering(Test<T>)
And the rewritten function template for class template partial specialization would be like this:
template<typename T>
void ordering(Test<T&&>)
According to the rule for "Deducing template arguments during partial ordering":
The types used to determine the ordering depend on the context in which the partial ordering is done:
In the context of a function call, the types used are those function parameter types for which the function call has arguments.
In the context of a call to a conversion function, the return types of the conversion function templates are used.
In other contexts the function template's function type is used.
Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types of P and A. If a particular P contains no template-parameters that participate in template argument deduction, that P is not used to determine the ordering.
Neither function call nor call to a conversion function is this context. So the bullet 3 works. That means, Take void(Test<T>) as P and Take void(Test<T&&>) as A, vice versa.
For this pair P/A, it is the case mentioned in temp.deduct.type#10, that is,
each parameter type Pi of the respective parameter-type-list ([dcl.fct]) of P is compared with the corresponding parameter type Ai of the corresponding parameter-type-list of A.
Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it P) is compared with an actual type (call it A), and an attempt is made to find template argument values (a type for a type parameter, a value for a non-type parameter, or a template for a template parameter) that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.
Here, we only have one parameter in each function type. So compare Test<T> with Test<T&&> and vice versa, such process are mentioned in temp.deduct.type#9.
However I argue here is that there's no relevant rule in the standard which says what's the detail about the comparison process. In other words, why we can deduce T from T&&(T would be T&&), But not the other way around. If I miss the relevant rules about the detail, please point it out. If there are indeed no such detail descriptions in the standard, where can I find the relevant technology about the detail of template argument deduction process?
It looks to me like what you've cited is a problem in what you're looking at, but it's already been noticed and fixed. In particular, you quote the following:
Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types of P and A. If a particular P contains no template-parameters that participate in template argument deduction, that P is not used to determine the ordering.
By N4800 (and maybe before--I haven't tracked down exactly when this was changed), this has been changed to the following (§[temp.deduct.partial]/4, 5):
4 Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types of P and A.
5 Before the partial ordering is done, certain transformations are performed on the types used for partial ordering:
(5.1) — If P is a reference type, P is replaced by the type referred to.
(5.2) — If A is a reference type, A is replaced by the type referred to.
This effectively removes the possibility of deducing T as a reference type, because the type from which it is deduced can never be a reference.
In [temp.deduct.call] and [temp.deduct.conv], it mentions that
In general, the deduction process attempts to find template argument
values that will make the deduced A identical to A.
I believe this rule is common knowledge so it is not mentioned in other sub-clauses (it is mentioned in the above two sub-clauses because there are exceptions in that two sub-clauses).
I'm having difficulty understanding the how formal ordering rules work as described in chapter 12 of the book C++ Templates, The Complete Guide by D. Vandevoorde and N. M. Josuttis. On page 188 of this book the authors give the following scenario used to decide which of two viable function templates is more specialized:
From these two templates we synthesize two lists of argument types by replacing the template parameters as described earlier: (A1) and (A2*) (where A1 and A2 are unique made up types). Clearly, deduction of the first template against the second list of argument types succeeds by substituting A2* for T. However, there is no way to make T* of the second template match the nonpointer type A1 in the first list. Hence, we formally conclude that the second template is more specialized than the first.
I'd like some understanding this example.
Edit
I believe that the two function templates referred to in the above quote are
template<typename T>
int f(T)
{
return 1;
}
template<typename T>
int f(T*)
{
return 2;
}
The rules are a bit harder to explain than to use. The idea is that a template is more specialized than another template if the set of possible instantiations of the more specialized is a strict subset of the set of possible instantiations of the less specialized one.
That is, every type that can be use as an argument to the more specialized can also be used as argument to the less specialized, and there is at least one type that can be used with the less specialized that cannot be used with the more specialized.
Given the two templates:
template <typename A> void f( A ); // [1]
template <typename B> void f( B* ); // [2]
The question to resolve is which one of them is more generic (i.e. can take a greater number of arguments). The whole description in the standard is done in terms of synthetic unique types that are used for A and B, but in a less precise way we can try to resolve by hand waving.
Say we find a type X that matches the second template argument, then an instantiation of that second template will look like void f( X* ) (besides the fact that it is a template). Now, can the template [1] be used to generate an equivalent function? Yes, by making A == X* in the type deduction. Can we do it in the opposite direction? Say we find a type Y with which we can instantiate the first template, we get void f( Y ). Can the second template match this call? No, only for the subset of types that are pointers the previous statement can hold.
That means that the second template is more specialized, since for every valid instantiation of the second template, we can also instantiate the first template, but there are some instantiations of the first template that would not be valid instantiations of the second.
For a practical example, f( char* ) can be matched by both templates, but f( 5 ) can only be matched by the first one. The reason for the weird explanation in terms of synthetic types is that a single example does not guarantee the order, it has to hold for all types. The synthetic type is a representative of any type.
I think the point of the authors is that T in the first template can be matched to both a type A and a pointer to a type A*, while the second template can only be matched to a pointer to a type A*, therefore the second template is more specialized.