[temp.fct] (original) (raw)
13.7.7.1 General [temp.fct.general]
A function template defines an unbounded set of related functions.
[Example 1:
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.139
13.7.7.2 Function template overloading [temp.over.link]
It is possible to overload function templates so that two different function template specializations have the same type.
[Example 1:
template<class T> void f(T*);void g(int* p) { f(p); }
template<class T> void f(T);void h(int* p) { f(p); }
— _end example_]
The signature of a function template is defined in [intro.defs].
The names of the template parameters are significant only for establishing the relationship between the template parameters and the rest of the signature.
[Note 1:
Two distinct function templates can have identical function return types and function parameter lists, even if overload resolution alone cannot distinguish them.
template<class T> void f();template<int I> void f(); — _end note_]
When an expression that references a template parameter is used in the function parameter list or the return type in the declaration of a function template, the expression that references the template parameter is part of the signature of the function template.
This is necessary to permit a declaration of a function template in one translation unit to be linked with another declaration of the function template in another translation unit and, conversely, to ensure that function templates that are intended to be distinct are not linked with one another.
[Example 2: template <int I, int J> A<I+J> f(A<I>, A<J>); template <int K, int L> A<K+L> f(A<K>, A<L>); template <int I, int J> A<I-J> f(A<I>, A<J>); — _end example_]
[Note 2:
Most expressions that use template parameters use non-type template parameters, but it is possible for an expression to reference a type parameter.
For example, a template type parameter can be used in thesizeof operator.
— _end note_]
Two expressions involving template parameters are consideredequivalentif two function definitions containing the expressions would satisfy the one-definition rule, except that the tokens used to name the template parameters may differ as long as a token used to name a template parameter in one expression is replaced by another token that names the same template parameter in the other expression.
Two unevaluated operands that do not involve template parameters are considered equivalent if two function definitions containing the expressions would satisfy the one-definition rule, except that the tokens used to name types and declarations may differ as long as they name the same entities, and the tokens used to form concept-ids may differ as long as the two template-ids are the same ([temp.type]).
[Note 3:
For instance, A<42> and A<40+2> name the same type.
— _end note_]
[Note 4:
The intent is to avoid lambda-expressions appearing in the signature of a function template with external linkage.
— _end note_]
For determining whether two dependent names ([temp.dep]) are equivalent, only the name itself is considered, not the result of name lookup in the context of the template.
If multiple declarations of the same function template differ in the result of this name lookup, the result for the first declaration is used.
[Example 3: template <int I, int J> void f(A<I+J>); template <int K, int L> void f(A<K+L>); template <class T> decltype(g(T())) h();int g(int);template <class T> decltype(g(T())) h() { return g(T()); } int i = h<int>(); template <int N> void foo(const char (*s)[([]{}, N)]);template <int N> void foo(const char (*s)[([]{}, N)]);template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]);template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]); — _end example_]
Two potentially-evaluated expressions involving template parameters that are not equivalent arefunctionally equivalentif, for any given set of template arguments, the evaluation of the expression results in the same value.
Two unevaluated operands that are not equivalent are functionally equivalent if, for any given set of template arguments, the expressions perform the same operations in the same order with the same entities.
[Note 5:
For instance, one could have redundant parentheses.
— _end note_]
Two template-parameters areequivalentunder the following conditions:
- they declare template parameters of the same kind,
- if either declares a template parameter pack, they both do,
- if they declare non-type template parameters, they have equivalent types ignoring the use of type-constraints for placeholder types, and
- if they declare template template parameters, their template parameters are equivalent.
When determining whether types or type-constraint_s_are equivalent, the rules above are used to compare expressions involving template parameters.
Two function templates areequivalentif they are declared in the same scope, have the same name, have equivalent template-heads, and have return types, parameter lists, and trailing requires-clauses (if any) that are equivalent using the rules described above to compare expressions involving template parameters.
Two function templates arefunctionally equivalentif they are declared in the same scope, have the same name, accept and are satisfied by the same set of template argument lists, and have return types and parameter lists that are functionally equivalent using the rules described above to compare expressions involving template parameters.
If the validity or meaning of the program depends on whether two constructs are equivalent, and they are functionally equivalent but not equivalent, the program is ill-formed, no diagnostic required.
[Note 6:
This rule guarantees that equivalent declarations will be linked with one another, while not requiring implementations to use heroic efforts to guarantee that functionally equivalent declarations will be treated as distinct.
For example, the last two declarations are functionally equivalent and would cause a program to be ill-formed: template <int I> void f(A<I>, A<I+10>);template <int I> void f(A<I>, A<I+10>);template <int I> void f(A<I>, A<I+10>);template <int I> void f(A<I>, A<I+11>);template <int I> void f(A<I>, A<I+10>);template <int I> void f(A<I>, A<I+1+2+3+4>);
— _end note_]
13.7.7.3 Partial ordering of function templates [temp.func.order]
If a function template is overloaded, the use of a function template specialization can be ambiguous because template argument deduction ([temp.deduct]) may associate the function template specialization with more than one function template declaration.
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 (includingtemplate parameter packsthereof) 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 1:
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 cvthat is a member of a class A:
- The type X(M) is “rvalue reference to cv A” if the optional ref-qualifier ofM 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 2:
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 1: struct A { };template<class T> struct B { template<class R> int operator*(R&); };template<class T, class R> int operator*(T&, R&); int main() { A a; B<A> b; b * a; } — _end example_]
Using the transformed function template's function type, perform type deduction against the other template as described in [temp.deduct.partial].
[Example 2: 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); float x; g(x); A<int> z; h(z); const A<int> z2; h(z2); } — _end example_]
[Note 3:
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 3: template<class T> void f(T); template<class T> void f(T*, int=1); template<class T> void g(T); template<class T> void g(T*, ...); int main() { int* ip; f(ip); g(ip); } — _end example_]
[Example 4: template<class T, class U> struct A { };template<class T, class U> void f(U, A<U, T>* p = 0); template< class U> void f(U, A<U, U>* p = 0); template<class T > void g(T, T = T()); template<class T, class... U> void g(T, U ...); void h() { f<int>(42, (A<int, int>*)0); f<int>(42); g(42); } — _end example_]
[Example 5: template<class T, class... U> void f(T, U...); template<class T > void f(T); template<class T, class... U> void g(T*, U...); template<class T > void g(T); void h(int i) { f(&i); g(&i); } — _end example_]
— _end note_]
If deduction against the other template succeeds for both transformed templates, constraints can be considered as follows:
- 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-listsuch that
* the corresponding template-parameter_s_of the template-parameter-lists are equivalent and
* the function parameters that positionally correspond between the two templates are of the same type,
neither template is more specialized than the other. - Otherwise, if the corresponding template-parameter_s_of the template-parameter-list_s_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.
- If exactly one of the templates was considered by overload resolution via a rewritten candidate with reversed order of parameters:
- 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 6: 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); } 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; } — _end example_]