what is the detail of template argument deduction process

315 views Asked by At
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?

2

There are 2 answers

7
xskxzr On

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

4
Jerry Coffin On

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.