13 Templates [temp]

13.7 Template declarations [temp.decls]

13.7.6 Function templates [temp.fct]

A function template defines an unbounded set of related functions.
Example
:
A family of sort functions might be declared like this:
template<class T> class Array { };
template<class T> void sort(Array<T>&);
— end example
 ]
A function template can be overloaded with other function templates and with non-template functions ([dcl.fct]).
A non-template function is not related to a function template (i.e., it is never considered to be a specialization), even if it has the same name and type as a potentially generated function template specialization.135
That is, declarations of non-template functions do not merely guide overload resolution of function template specializations with the same name.
If such a non-template function is odr-used in a program, it must be defined; it will not be implicitly instantiated using the function template definition.

13.7.6.2 Partial ordering of function templates [temp.func.order]

If a function template is overloaded, the use of a function template specialization might be ambiguous because template argument deduction may associate the function template specialization with more than one function template declaration.
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:
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.
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
 ]
Each function template M that is a member function is considered to have a new first parameter of type X(M), described below, inserted in its function parameter list.
If exactly one of the function templates was considered by overload resolution via a rewritten candidate ([over.match.oper]) with a reversed order of parameters, then the order of the function parameters in its transformed template is reversed.
For a function template M with cv-qualifiers cv that is a member of a class A:
  • The type X(M) is “rvalue reference to cv A” if the optional ref-qualifier of M is && or if M has no ref-qualifier and the positionally-corresponding parameter of the other transformed template has rvalue reference type; if this determination depends recursively upon whether X(M) is an rvalue reference type, it is not considered to have rvalue reference type.
  • Otherwise, X(M) is “lvalue reference to cv A.
Note
:
This allows a non-static member to be ordered with respect to a non-member function and for the results to be equivalent to the ordering of two equivalent non-members.
— end note
 ]
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 declaration of B​::​operator* is transformed into the equivalent of
// template<class R> int operator*(B<A>&, R&);      // #1a

int main() {
  A a;
  B<A> b;
  b * a;                                            // calls #1
}
— end example
 ]
Using the transformed function template's function type, perform type deduction against the other template as described in [temp.deduct.partial].
Example
:
template<class T> struct A { A(); };

template<class T> void f(T);
template<class T> void f(T*);
template<class T> void f(const T*);

template<class T> void g(T);
template<class T> void g(T&);

template<class T> void h(const T&);
template<class T> void h(A<T>&);

void m() {
  const int* p;
  f(p);             // f(const T*) is more specialized than f(T) or f(T*)
  float x;
  g(x);             // ambiguous: g(T) or g(T&)
  A<int> z;
  h(z);             // overload resolution selects h(A<T>&)
  const A<int> z2;
  h(z2);            // h(const T&) is called because h(A<T>&) is not callable
}
— end example
 ]
Note
:
Since, in a call context, such type deduction considers only parameters for which there are explicit call arguments, some parameters are ignored (namely, function parameter packs, parameters with default arguments, and ellipsis parameters).
Example
:
template<class T> void f(T);                            // #1
template<class T> void f(T*, int=1);                    // #2
template<class T> void g(T);                            // #3
template<class T> void g(T*, ...);                      // #4

int main() {
  int* ip;
  f(ip);                                                // calls #2
  g(ip);                                                // calls #4
}
— end example
 ]
Example
:
template<class T, class U> struct A { };

template<class T, class U> void f(U, A<U, T>* p = 0);   // #1
template<         class U> void f(U, A<U, U>* p = 0);   // #2
template<class T         > void g(T, T = T());          // #3
template<class T, class... U> void g(T, U ...);         // #4

void h() {
  f<int>(42, (A<int, int>*)0);                          // calls #2
  f<int>(42);                                           // error: ambiguous
  g(42);                                                // error: ambiguous
}
— end example
 ]
Example
:
template<class T, class... U> void f(T, U...);          // #1
template<class T            > void f(T);                // #2
template<class T, class... U> void g(T*, U...);         // #3
template<class T            > void g(T);                // #4

void h(int i) {
  f(&i);                                                // OK: calls #2
  g(&i);                                                // OK: calls #3
}
— end example
 ]
— end note
 ]
If deduction against the other template succeeds for both transformed templates, constraints can be considered as follows:
  • If their template-parameter-lists (possibly including template-parameters invented for an abbreviated function template ([dcl.fct])) or function parameter lists differ in length, neither template is more specialized than the other.
  • Otherwise:
    • If exactly one of the templates was considered by overload resolution via a rewritten candidate with reversed order of parameters:
      • If, for either template, some of the template parameters are not deducible from their function parameters, neither template is more specialized than the other.
      • If there is either no reordering or more than one reordering of the associated template-parameter-list such that neither template is more specialized than the other.
    • Otherwise, if the corresponding template-parameters of the template-parameter-lists are not equivalent ([temp.over.link]) or if the function parameters that positionally correspond between the two templates are not of the same type, neither template is more specialized than the other.
  • Otherwise, if the context in which the partial ordering is done is that of a call to a conversion function and the return types of the templates are not the same, then neither template is more specialized than the other.
  • Otherwise, if one template is more constrained than the other ([temp.constr.order]), the more constrained template is more specialized than the other.
  • Otherwise, neither template is more specialized than the other.
Example
:
template <typename> constexpr bool True = true;
template <typename T> concept C = True<T>;

void f(C auto &, auto &) = delete;
template <C Q> void f(Q &, C auto &);

void g(struct A *ap, struct B *bp) {
  f(*ap, *bp);                  // OK: Can use different methods to produce template parameters
}

template <typename T, typename U> struct X {};

template <typename T, C U, typename V> bool operator==(X<T, U>, V) = delete;
template <C T, C U, C V>               bool operator==(T, X<U, V>);

void h() {
  X<void *, int>{} == 0;        // OK: Correspondence of [T, U, V] and [U, V, T]
}
— end example
 ]