Document number:  02-0051/N1393
Date:  September 9, 2002
Author:  John Spicer, Edison Design Group
 jhs@edg.com
Author:  John Wiegley, Borland
 johnw@gnu.org

Revisions to Partial Ordering Rules (issue 214)

Introduction

The description of partial ordering as described in the standard suffers from a number of problems:

  1. The specification is incomplete. In particular, the way in which partial ordering interfaces with the argument deduction rules is unspecified.
  2. The rules fail to account for templates in which some template parameters are not used in the parameter and/or return types but instead must be explicitly specified on the call.
  3. The current (understood) rules do not correctly deal with comparison of templates where one of the parameter types is a cv-qualified reference. I say "understood" because it could be argued that the current rules are not complete enough to know for sure how such cases are to be handled. But the generally accepted understanding of the current rules does not produce the desired results.

With respect to #3 above, consider this case:

template <class T> struct A {}; template <class T> void f(const T&); // #1 template <class T> void f(A<T>); // #2 template <class T> void g(const T&); // #3 template <class T> void g(T); // #4 int main() { A<int> ai; f(ai); // should call #2 g(ai); // should call #3 }

The original proposal for partial ordering removed top-level references and then top-level cv-qualifiers. This had the property that the call of f produced the desired result but the call of g was ambiguous. The current (understood) rules are that top-level cv-qualifiers are removed before top-level references. This makes the call of g work but breaks f. The rules proposed by this paper provide a mechanism that makes both f and g work without breaking any cases that worked previously.

Standard Changes

Change 14.5.5.2 paragraph 2 to read:

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 parameter types, or in the case of a conversion function the return type. If the deduction succeeds, the transformed function is said to be at least as specialized as the other. If one function is at least as specialized as the other, and the other is not at least as specialized as the first, then the first is more specialized.

Change 14.5.5.2 paragraph 3 to read:

To produce the transformed template, for each type, non-type, or template template parameter synthesize a unique type, value, or class template respectively and substitute that for each occurrence of that parameter in the function type of the template.

Change 14.5.5.2 paragraph 4 to read (note: the section reference should refer to the section added to 14.8.2 below):

Using the transformed function template's function parameter list, or in the case of a conversion function its transformed return type, perform type deduction against the function parameter list (or return type) of the other function. The transformed function is at least as specialized as the other if, and only if, the deduction succeeds and the deduced parameter types (or return type) match the other function's parameter types (or return type) in such a way that no implicit type conversions are required. The mechanism for performing these deductions is given in 14.8.2.x.

Insert the following section before 14.8.2.4 (temp.deduct.type): (Note that this would either be a new 14.8.2.4, or would be given a number like 14.8.2.3a. If neither of these is possible from a troff point of view, this could be made 14.8.2.5)

Deducing template arguments when determining the partial ordering of function templates (temp.deduct.partial)

Template argument deduction is done by comparing certain types associated with the parameter template with the corresponding types from the argument 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 creation of the transformed type is described in 14.5.5.2). 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 template-1 as the argument template and template-2 as the parameter template and again using 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:

Each type from the parameter template and the corresponding type from the argument template are used as the types of P and A.

Before the partial ordering is done, certain transformations are performed on the types used for partial ordering:

If both P and A were reference types (before being replaced with the type referred to above), determine which of the two types (if any) is more cv-qualified than the other; otherwise the types are considered to be equally cv-qualified for partial ordering purposes. The result of this determination will be used later.

Remove any top-level cv-qualifiers:

Using the resulting types P and A the deduction is then done as described in (temp.deduct.type).

If, for a given type, deduction succeeds in both directions (i.e., the types are identical after the transformations above) the more cv-qualified type is considered to be more specialized.

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. [Note: A template parameter used in a non-deduced context is considered used.]

End of document.