17 Templates [temp]

17.6 Template declarations [temp.decls]

17.6.6 Function templates [temp.fct]

17.6.6.1 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
:
// translation unit 1:
template<class T>
  void f(T*);
void g(int* p) {
  f(p); // calls f<int>(int*)
}
// translation unit 2:
template<class T>
  void f(T);
void h(int* p) {
  f(p); // calls f<int*>(int*)
}
end example
]
Such specializations are distinct functions and do not violate the one-definition rule.
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
:
Two distinct function templates may 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();       // OK: overloads the first template
                                // distinguishable with an explicit template argument list
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
:
template <int I, int J> A<I+J> f(A<I>, A<J>);   // #1
template <int K, int L> A<K+L> f(A<K>, A<L>);   // same as #1
template <int I, int J> A<I-J> f(A<I>, A<J>);   // different from #1
end example
]
[Note
:
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 the sizeof operator.
end note
]
Two expressions involving 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 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.
For determining whether two dependent names 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
:
template <int I, int J> void f(A<I+J>);         // #1
template <int K, int L> void f(A<K+L>);         // same as #1

template <class T> decltype(g(T())) h();
int g(int);
template <class T> decltype(g(T())) h()         // redeclaration of h() uses the earlier lookup…
  { return g(T()); }                            // … although the lookup here does find g(int)
int i = h<int>();                               // template argument substitution fails; g(int)
                                                // was not in scope at the first declaration of h()
end example
]
Two expressions involving template parameters that are not equivalent are functionally equivalent if, for any given set of template arguments, the evaluation of the expression results in the same value.
Two template-heads are equivalent if their template-parameter-lists have the same length, corresponding template-parameters are equivalent, and if either has a requires-clause, they both have requires-clauses and the corresponding constraint-expressions are equivalent.
Two template-parameters are equivalent under 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,
  • if they declare template template parameters, their template parameters are equivalent, and
  • if either is declared with a qualified-concept-name, they both are, and the qualified-concept-names are equivalent.
When determining whether types or qualified-concept-names are equivalent, the rules above are used to compare expressions involving template parameters.
Two template-heads are functionally equivalent if they accept and are satisfied by ([temp.constr.constr]) the same set of template argument lists.
Two function templates are equivalent if 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 are functionally equivalent if 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
:
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:
// guaranteed to be the same
template <int I> void f(A<I>, A<I+10>);
template <int I> void f(A<I>, A<I+10>);

// guaranteed to be different
template <int I> void f(A<I>, A<I+10>);
template <int I> void f(A<I>, A<I+11>);

// ill-formed, no diagnostic required
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
]