[temp.deduct] (original) (raw)
13 Templates [temp]
13.10 Function template specializations [temp.fct.spec]
13.10.3 Template argument deduction [temp.deduct]
13.10.3.1 General [temp.deduct.general]
When a function template specialization is referenced, all of the template arguments shall have values.
The values can be explicitly specified or, in some cases, be deduced from the use or obtained from defaulttemplate-arguments.
[Example 1:
void f(Array<dcomplex>& cv, Array<int>& ci) { sort(cv); sort(ci); } andvoid g(double d) { int i = convert<int>(d); int c = convert<char>(d); }
— _end example_]
When an explicit template argument list is specified, if the given template-id is not valid ([temp.names]), type deduction fails.
Otherwise, the specified template argument values are substituted for the corresponding template parameters as specified below.
After this substitution is performed, the function parameter type adjustments described in [dcl.fct] are performed.
[Example 2:
A parameter type of “void (const int, int[5])” becomes “void(*)(int,int*)”.
— _end example_]
[Note 1:
A top-level qualifier in a function parameter declaration does not affect the function type but still affects the type of the function parameter variable within the function.
— _end note_]
[Example 3: template <class T> void f(T t);template <class X> void g(const X x);template <class Z> void h(Z, Z*);int main() { f<int>(1); f<const int>(1); g<int>(1); g<const int>(1); h<const int>(1,0);} — _end example_]
[Note 2:
f<int>(1) and f<const int>(1) call distinct functions even though both of the functions called have the same function type.
— _end note_]
The resulting substituted and adjusted function type is used as the type of the function template for template argument deduction.
If a template argument has not been deduced and its corresponding template parameter has a default argument, the template argument is determined by substituting the template arguments determined for preceding template parameters into the default argument.
If the substitution results in an invalid type, as described above, type deduction fails.
[Example 4: template <class T, class U = double> void f(T t = 0, U u = 0);void g() { f(1, 'c'); f(1); f(); f<int>(); f<int,char>(); } — _end example_]
When all template arguments have been deduced or obtained from default template arguments, all uses of template parameters in the template parameter list of the template are replaced with the corresponding deduced or default argument values.
If the substitution results in an invalid type, as described above, type deduction fails.
If the constraints are not satisfied, type deduction fails.
In the context of a function call, if type deduction has not yet failed, then for those function parameters for which the function call has arguments, each function parameter with a type that was non-dependent before substitution of any explicitly-specified template arguments is checked against its corresponding argument; if the corresponding argument cannot be implicitly converted to the parameter type, type deduction fails.
[Note 3:
Overload resolution will check the other parameters, including parameters with dependent types in which no template parameters participate in template argument deduction and parameters that became non-dependent due to substitution of explicitly-specified template arguments.
— _end note_]
If type deduction has not yet failed, then all uses of template parameters in the function type are replaced with the corresponding deduced or default argument values.
If the substitution results in an invalid type, as described above, type deduction fails.
[Example 5: template <class T> struct Z { typedef typename T::x xx;};template <class T> concept C = requires { typename T::A; };template <C T> typename Z<T>::xx f(void *, T); template <class T> void f(int, T); struct A {} a;struct ZZ { template <class T, class = typename Z<T>::xx> operator T *();operator int();};int main() { ZZ zz; f(1, a); f(zz, 42); } — _end example_]
At certain points in the template argument deduction process it is necessary to take a function type that makes use of template parameters and replace those template parameters with the corresponding template arguments.
This is done at the beginning of template argument deduction when any explicitly specified template arguments are substituted into the function type, and again at the end of template argument deduction when any template arguments that were deduced or obtained from default arguments are substituted.
The substitution occurs in all types and expressions that are used in the deduction substitution loci.
The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions) inside sizeof, decltype, and other contexts that allow non-constant expressions.
The substitution proceeds in lexical order and stops when a condition that causes deduction to fail is encountered.
If substitution into different declarations of the same function template would cause template instantiations to occur in a different order or not at all, the program is ill-formed; no diagnostic required.
[Example 6: template <class T> struct A { using X = typename T::X; };template <class T> typename T::X f(typename A<T>::X);template <class T> void f(...) { } template <class T> auto g(typename A<T>::X) -> typename T::X;template <class T> void g(...) { } template <class T> typename T::X h(typename A<T>::X);template <class T> auto h(typename A<T>::X) -> typename T::X; template <class T> void h(...) { } void x() { f<int>(0); g<int>(0); h<int>(0); } — _end example_]
If a substitution results in an invalid type or expression, type deduction fails.
An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written in the same context using the substituted arguments.
[Note 5:
If no diagnostic is required, the program is still ill-formed.
Access checking is done as part of the substitution process.
— _end note_]
Invalid types and expressions can result in a deduction failure only in the immediate context of the deduction substitution loci.
[Note 6:
The substitution into types and expressions can result in effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc.
Such effects are not in the “immediate context” and can result in the program being ill-formed.
— _end note_]
When substituting into a lambda-expression, substitution into its body is not in the immediate context.
[Note 7:
The intent is to avoid requiring implementations to deal with substitution failure involving arbitrary statements.
[Example 7: template <class T> auto f(T) -> decltype([]() { T::invalid; } ());void f(...); f(0); template <class T, std::size_t = sizeof([]() { T::invalid; })> void g(T);void g(...); g(0); template <class T> auto h(T) -> decltype([x = T::invalid]() { });void h(...); h(0); template <class T> auto i(T) -> decltype([]() -> typename T::invalid { });void i(...); i(0); template <class T> auto j(T t) -> decltype([](auto x) -> decltype(x.invalid) { } (t)); void j(...); j(0); — _end example_]
— _end note_]
[Example 8: struct X { };struct Y { Y(X) {} };template <class T> auto f(T t1, T t2) -> decltype(t1 + t2); X f(Y, Y); X x1, x2; X x3 = f(x1, x2); — _end example_]
[Note 8:
Type deduction can fail for the following reasons:
- Attempting to instantiate a pack expansion containing multiple packs of differing lengths.
- Attempting to create an array with an element type that is void, a function type, or a reference type, or attempting to create an array with a size that is zero or negative.
[Example 9: template <class T> int f(T[5]);int I = f<int>(0);int j = f<void>(0); — _end example_] - Attempting to use a type that is not a class or enumeration type in a qualified name.
[Example 10: template <class T> int f(typename T::B*);int i = f<int>(0); — _end example_] - Attempting to use a type in a nested-name-specifier of aqualified-id when that type does not contain the specified member, or
- the specified member is not a type where a type is required, or
- the specified member is not a template where a template is required, or
- the specified member is not a non-type, non-template where a non-type, non-template is required.
[Example 11: template <int I> struct X { };template <template <class T> class> struct Z { };template <class T> void f(typename T::Y*) {} template <class T> void g(X<T::N>*) {} template <class T> void h(Z<T::TT>*) {} struct A {};struct B { int Y; };struct C { typedef int N;};struct D { typedef int TT;};int main() { f<A>(0); f<B>(0); g<C>(0); h<D>(0); } — _end example_]
- Attempting to create a pointer to reference type.
- Attempting to create a reference to void.
- Attempting to create “pointer to member of T” when T is not a class type.
[Example 12: template <class T> int f(int T::*);int i = f<int>(0); — _end example_] - Attempting to give an invalid type to a constant template parameter.
[Example 13: template <class T, T> struct S {};template <class T> int f(S<T, T{}>*); class X { int m;};int i0 = f<X>(0); — _end example_] - Attempting to perform an invalid conversion in either a template argument expression, or an expression used in the function declaration.
[Example 14: template <class T, T*> int f(int);int i2 = f<int,1>(0); — _end example_] - Attempting to create a function type in which a parameter has a type of void, or in which the return type is a function type or array type.
- Attempting to give to an explicit object parameter of a lambda's function call operator a type not permitted for such ([expr.prim.lambda.closure]).
— _end note_]
template <int> int f(int);template <signed char> int f(int);int i1 = f<1000>(0); int i2 = f<1>(0); — _end example_]
13.10.3.2 Deducing template arguments from a function call [temp.deduct.call]
Template argument deduction is done by comparing each function template parameter type (call itP) that contains template parameters that participate in template argument deduction with the type of the corresponding argument of the call (call itA) as described below.
If removing references and cv-qualifiers from P givesor for some and N and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list independently, taking as separate function template parameter types and the initializer element as the corresponding argument.
In the case, if N is a constant template parameter,N is deduced from the length of the initializer list.
Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context ([temp.deduct.type]).
[Example 1: template<class T> void f(std::initializer_list<T>); f({1,2,3}); f({1,"asdf"}); template<class T> void g(T); g({1,2,3}); template<class T, int N> void h(T const(&)[N]); h({1,2,3}); template<class T> void j(T const(&)[3]); j({42}); struct Aggr { int i; int j; };template<int N> void k(Aggr const(&)[N]); k({1,2,3}); k({{1},{2},{3}}); template<int M, int N> void m(int const(&)[M][N]); m({{1,2},{3,4}}); template<class T, int N> void n(T const(&)[N], T); n({{1},{2},{3}},Aggr()); template<typename T, int N> void o(T (* const (&)[N])(T)) { } int f1(int);int f4(int);char f4(char); o({ &f1, &f4 }); o({ &f1, static_cast<char(*)(char)>(&f4) }); — _end example_]
For a function parameter pack that occurs at the end of the parameter-declaration-list, deduction is performed for each remaining argument of the call, taking the type Pof the declarator-id of the function parameter pack as the corresponding function template parameter type.
Each deduction deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack.
When a function parameter pack appears in a non-deduced context ([temp.deduct.type]), the type of that pack is never deduced.
[Example 2: template<class ... Types> void f(Types& ...);template<class T1, class ... Types> void g(T1, Types ...);template<class T1, class ... Types> void g1(Types ..., T1);void h(int x, float& y) { const int z = x; f(x, y, z); g(x, y, z); g1(x, y, z); g1<int, int, int>(x, y, z); } — _end example_]
IfPis not a reference type:
- IfAis an array type, the pointer type produced by the array-to-pointer standard conversion is used in place ofAfor type deduction; otherwise,
- IfAis a function type, the pointer type produced by thefunction-to-pointer standard conversion is used in place ofAfor type deduction; otherwise,
- IfAis a cv-qualified type, the top-level cv-qualifiers ofA's type are ignored for type deduction.
IfPis a cv-qualified type, the top-level cv-qualifiers ofP's type are ignored for type deduction.
IfPis a reference type, the type referred to byPis used for type deduction.
[Example 3: template<class T> int f(const T&);int n1 = f(5); const int i = 0;int n2 = f(i); template <class T> int g(volatile T&);int n3 = g(i); — _end example_]
A forwarding referenceis an rvalue reference to a cv-unqualified template parameter that does not represent a template parameter of a class template (during class template argument deduction ([over.match.class.deduct])).
If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.
[Example 4: template <class T> int f(T&& heisenreference);template <class T> int g(const T&&);int i;int n1 = f(i); int n2 = f(0); int n3 = g(i); template <class T> struct A { template <class U> A(T&&, U&&, int*); A(T&&, int*); };template <class T> A(T&&, int*) -> A<T>; int *ip; A a{i, 0, ip}; A a0{0, 0, ip}; A a2{i, ip}; — _end example_]
In general, the deduction process attempts to find template argument values that will make the deducedAidentical toA(after the typeAis transformed as described above).
However, there are three cases that allow a difference:
- If the originalPis a reference type, the deducedA(i.e., the type referred to by the reference) can be more cv-qualified than the transformed A.
- IfPis a class andPhas the formsimple-template-id, then the transformed Acan be a derived class D of the deducedA.
Likewise, ifPis a pointer to a class of the formsimple-template-id, the transformed Acan be a pointer to a derived class D pointed to by the deducedA.
However, if there is a class C that is a (direct or indirect) base class of D and derived (directly or indirectly) from a class B and that would be a valid deduced A, the deduced A cannot be B or pointer to B, respectively.
[Example 5: template <typename... T> struct X;template <> struct X<> {};template <typename T, typename... Ts> struct X<T, Ts...> : X<Ts...> {};struct D : X<int> {};struct E : X<>, X<int> {};template <typename... T> int f(const X<T...>&);int x = f(D()); int z = f(E()); — _end example_]
These alternatives are considered only if type deduction would otherwise fail.
If they yield more than one possible deducedA, the type deduction fails.
[Note 1:
If a template parameter is not used in any of the function parameters of a function template, or is used only in a non-deduced context, its correspondingtemplate-argumentcannot be deduced from a function call and thetemplate-argumentmust be explicitly specified.
— _end note_]
WhenPis a function type, function pointer type, or pointer-to-member-function type:
- If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.
- If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set whose associated constraints ([temp.constr.constr]) are satisfied.
If all successful deductions yield the same deduced A, that deduced A is the result of deduction; otherwise, the parameter is treated as a non-deduced context.
[Example 6: template <class T> int f(T (*p)(T));int g(int);int g(char);int i = f(g); — _end example_]
[Example 7: template <class T> int f(T, T (*p)(T));int g(int);char g(char);int i = f(1, g); — _end example_]
[Example 8: template <class T> int f(T, T (*p)(T));char g(char);template <class T> T g(T);int i = f(1, g); — _end example_]
[Example 9: template<bool B> struct X { static void f(short) requires B; static void f(short); };void test() { auto x = &X<true>::f; auto y = &X<false>::f; } — _end example_]
13.10.3.3 Deducing template arguments taking the address of a function template [temp.deduct.funcaddr]
Template arguments can be deduced from the type specified when taking the address of an overload set.
If there is a target, the function template's function type and the target type are used as the types ofPandA, and the deduction is done as described in [temp.deduct.type].
Otherwise, deduction is performed with empty sets of types P and A.
A placeholder type ([dcl.spec.auto]) in the return type of a function template is a non-deduced context.
If template argument deduction succeeds for such a function, the return type is determined from instantiation of the function body.
13.10.3.4 Deducing conversion function template arguments [temp.deduct.conv]
Template argument deduction is done by comparing the return type of the conversion function template (call itP) with the type specified by the conversion-type-id of theconversion-function-id being looked up (call it A) as described in [temp.deduct.type].
If P is a reference type, the type referred to by P is used in place of P for type deduction and for any further references to or transformations ofP in the remainder of this subclause.
IfAis not a reference type:
- IfPis an array type, the pointer type produced by thearray-to-pointer standard conversion is used in place ofPfor type deduction; otherwise,
- IfPis a function type, the pointer type produced by thefunction-to-pointer standard conversion is used in place ofPfor type deduction; otherwise,
- IfPis a cv-qualified type, the top-level cv-qualifiers ofP's type are ignored for type deduction.
IfAis a cv-qualified type, the top-level cv-qualifiers ofA's type are ignored for type deduction.
IfAis a reference type, the type referred to byAis used for type deduction.
In general, the deduction process attempts to find template argument values that will make the deducedAidentical toA.
However, certain attributes of A may be ignored:
- If the original A is a reference type, any cv-qualifiers of A(i.e., the type referred to by the reference).
- If the original A is a function pointer or pointer-to-member-function type with a potentially-throwing exception specification ([except.spec]), the exception specification.
- Any cv-qualifiers in Athat can be restored by a qualification conversion.
These attributes are ignored only if type deduction would otherwise fail.
If ignoring them allows more than one possible deducedA, the type deduction fails.
13.10.3.5 Deducing template arguments during partial ordering [temp.deduct.partial]
Template argument deduction is done by comparing certain types associated with the two function templates being compared.
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.
[Note 1:
The creation of the transformed type is described in [temp.func.order].
— _end note_]
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 the transformed template-1 as the argument template and template-2 as the parameter template and again using the transformed 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:
- In the context of a function call, the types used are those function parameter types for which the function call has arguments.119
- In the context of a call to a conversion function, the return types of the conversion function templates are used.
Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types ofPandA.
Before the partial ordering is done, certain transformations are performed on the types used for partial ordering:
- IfPis a reference type,Pis replaced by the type referred to.
- IfAis a reference type,Ais replaced by the type referred to.
If bothPandAwere 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 below.
Remove any top-level cv-qualifiers:
- IfPis a cv-qualified type,Pis replaced by the cv-unqualified version ofP.
- IfAis a cv-qualified type,Ais replaced by the cv-unqualified version ofA.
Using the resulting typesPandA, the deduction is then done as described in [temp.deduct.type].
If P is a function parameter pack, the type A of each remaining parameter type of the argument template is compared with the type P of the declarator-id of the function parameter pack.
Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack.
Similarly, if A was transformed from a function parameter pack, it is compared with each remaining parameter type of the parameter template.
If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template.
[Example 1: template<class... Args> void f(Args... args); template<class T1, class... Args> void f(T1 a1, Args... args); template<class T1, class T2> void f(T1 a1, T2 a2); f(); f(1, 2, 3); f(1, 2); — _end example_]
If, for a given type, the types are identical after the transformations above and both P and A were reference types (before being replaced with the type referred to above):
- if the type from the argument template was an lvalue reference and the type from the parameter template was not, the parameter type is not considered to be at least as specialized as the argument type; otherwise,
- if the type from the argument template is more cv-qualified than the type from the parameter template (as described above), the parameter type is not considered to be at least as specialized as the argument type.
Function template Fis at least as specialized asfunction template G if, for each pair of types used to determine the ordering, the type from Fis at least as specialized as the type from G.
Fis more specialized than G ifFis at least as specialized asG andGis not at least as specialized asF.
If, after considering the above, function template Fis at least as specialized as function template G and vice-versa, and if G has a trailing function parameter pack for which F does not have a corresponding parameter, and if F does not have a trailing function parameter pack, then F is more specialized than G.
In most cases, deduction fails if not all template parameters have values, 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 2:
A template parameter used in a non-deduced context is considered used.
— _end note_]
[Example 2: template <class T> T f(int); template <class T, class U> T f(U); void g() { f<int>(1); } — _end example_]
[Note 3:
Partial ordering of function templates containing template parameter packs is independent of the number of deduced arguments for those template parameter packs.
— _end note_]
[Example 3: template<class ...> struct Tuple { };template<class ... Types> void g(Tuple<Types ...>); template<class T1, class ... Types> void g(Tuple<T1, Types ...>); template<class T1, class ... Types> void g(Tuple<T1, Types& ...>); g(Tuple<>()); g(Tuple<int, float>()); g(Tuple<int, float&>()); g(Tuple<int>()); — _end example_]
13.10.3.6 Deducing template arguments from a type [temp.deduct.type]
Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call itP) is compared with an actual type (call itA), and an attempt is made to find template argument values (a type for a type parameter, a value for a constant template parameter, or a template for a template template parameter) that will makeP, after substitution of the deduced values (call it the deducedA), compatible withA.
In some cases, the deduction is done using a single set of typesPandA, in other cases, there will be a set of corresponding typesPandA.
Type deduction is done independently for eachP/Apair, and the deduced template argument values are then combined.
If type deduction cannot be done for anyP/Apair, or if for any pair the deduction leads to more than one possible set of deduced values, or if different pairs yield different deduced values, or if any template argument remains neither deduced nor explicitly specified, template argument deduction fails.
The type of a type parameter is only deduced from an array bound if it is not otherwise deduced.
A given typePcan be composed from a number of other types, templates, and constant template argument values:
- A function type includes the types of each of the function parameters, the return type, and its exception specification.
- A pointer-to-member type includes the type of the class object pointed to and the type of the member pointed to.
- A type that is a specialization of a class template (e.g.,A<int>) includes the types, templates, and constant template argument values referenced by the template argument list of the specialization.
- An array type includes the array element type and the value of the array bound.
In most cases, the types, templates, and constant template argument values that are used to composePparticipate in template argument deduction.
That is, they may be used to determine the value of a template argument, and template argument deduction fails if the value so determined is not consistent with the values determined elsewhere.
In certain contexts, however, the value does not participate in type deduction, but instead uses the values of template arguments that were either deduced elsewhere or explicitly specified.
If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
[Note 1:
Under [temp.deduct.call], if P contains no template parameters that appear in deduced contexts, no deduction is done, so P and Aneed not have the same form.
— _end note_]
The non-deduced contexts are:
- A constant template argument or an array bound in which a subexpression references a template parameter.
- A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
- A function parameter for which the associated argument is an overload set such that one or more of the following apply:
- functions whose associated constraints are satisfied and that do not all have the same function type match the function parameter type (resulting in an ambiguous deduction), or
- no function whose associated constraints are satisfied matches the function parameter type, or
- the overload set supplied as an argument contains one or more function templates.
[Note 2:
A particular function from the overload set is selected ([over.over]) after template argument deduction has succeeded ([temp.over]).
— _end note_]
- A function parameter for which the associated argument is an initializer list ([dcl.init.list]) but the parameter does not have a type for which deduction from an initializer list is specified ([temp.deduct.call]).
[Example 1: template<class T> void g(T); g({1,2,3}); — _end example_]
When a type name is specified in a way that includes a non-deduced context, all of the types that comprise that type name are also non-deduced.
However, a compound type can include both deduced and non-deduced types.
[Example 2:
If a type is specified asA<T>::B<T2>, bothTandT2are non-deduced.
Likewise, if a type is specified asA<I+J>::X<T>,I,J, andTare non-deduced.
If a type is specified asvoid f(typename A<T>::B, A<T>), theTinA<T>::Bis non-deduced but theTinA<T>is deduced.
— _end example_]
[Example 3:
Here is an example in which different parameter/argument pairs produce inconsistent template argument deductions:template<class T> void f(T x, T y) { } struct A { };struct B : A { };void g(A a, B b) { f(a,b); f(b,a); f(a,a); f(b,b); }
Here is an example where two template arguments are deduced from a single function parameter/argument pair.
This can lead to conflicts that cause type deduction to fail:template <class T, class U> void f(T (*)(T, U, U));int g1(int, float, float);char g2(int, float, float);int g3(int, char, float);void r() { f(g1); f(g2); f(g3); }
Here is an example where the exception specification of a function type is deduced:template<bool E> void f1(void (*)() noexcept(E));template<bool> struct A { };template<bool B> void f2(void (*)(A<B>) noexcept(B));void g1();void g2() noexcept;void g3(A<true>);void h() { f1(g1); f1(g2); f2(g3); }
Here is an example where a qualification conversion applies between the argument type on the function call and the deduced template argument type:template<class T> void f(const T*) { } int* p;void s() { f(p); }
Here is an example where the template argument is used to instantiate a derived class type of the corresponding function parameter type:template <class T> struct B { };template <class T> struct D : public B<T> {};struct D2 : public B<int> {};template <class T> void f(B<T>&) {} void t() { D<int> d; D2 d2; f(d); f(d2); }
— _end example_]
A type template argumentT, a template template argumentTT denoting a class template or an alias template, a template template argumentVV denoting a variable template or a concept, or a constant template argumentican be deduced ifPandAhave one of the following forms:cv T T*T&T&&T[i]T(T) noexcept(i)T T::*TT<T>TT<i>TT<TT>TT<VV>TT<> where
- T represents a type or parameter-type-list that either satisfies these rules recursively, is a non-deduced context in P or A, or is the same non-dependent type in P and A,
- TT represents either a class template or a template template parameter,
- i represents an expression that either is an i, is value-dependent in P or A, or has the same constant value in P and A, and
- noexcept(i) represents an exception specification ([except.spec]) in which the (possibly-implicit, see [dcl.fct])noexcept-specifier's operand satisfies the rules for an i above.
[Note 3:
If a type matches such a form but contains noTs, is, or TTs, deduction is not possible.
— _end note_]
Similarly,<X> represents template argument lists where at least one argument contains an X, whereX is one of T, i, TT, or VV; and<>represents template argument lists where no argument contains aT, an i, a TT, or a VV.
If P has a form that contains<T>, <i>, <TT>, or <VV>, then each argument of the respective template argument list of P is compared with the corresponding argument of the corresponding template argument list of A.
If the template argument list of P contains a pack expansion that is not the last template argument, the entire template argument list is a non-deduced context.
If is a pack expansion, then the pattern of is compared with each remaining argument in the template argument list of A.
Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by .
During partial ordering, if was originally a pack expansion:
- if P does not contain a template argument corresponding to then is ignored;
- otherwise, if is not a pack expansion, template argument deduction fails.
[Example 4: template<class T1, class... Z> class S; template<class T1, class... Z> class S<T1, const Z&...> { }; template<class T1, class T2> class S<T1, const T2&> { }; S<int, const int&> s; template<class T, class... U> struct A { }; template<class T1, class T2, class... U> struct A<T1, T2*, U...> { }; template<class T1, class T2> struct A<T1, T2> { }; template struct A<int, int*>; — _end example_]
Similarly, if P has a form that contains(T), then each parameter type of the respective parameter-type-list ([dcl.fct]) ofP is compared with the corresponding parameter type of the corresponding parameter-type-list of A.
If P and A are function types that originated from deduction when taking the address of a function template ([temp.deduct.funcaddr]) or when deducing template arguments from a function declaration ([temp.deduct.decl]) and and are parameters of the top-level parameter-type-list of P and A, respectively, is adjusted if it is a forwarding reference ([temp.deduct.call]) and is an lvalue reference, in which case the type of is changed to be the template parameter type (i.e., T&& is changed to simply T).
[Note 4:
As a result, when is T&&and is X&, the adjusted will be T, causing T to be deduced as X&.
— _end note_]
[Example 5: template <class T> void f(T&&);template <> void f(int&) { } template <> void f(int&&) { } void g(int i) { f(i); f(0); } — _end example_]
If the parameter-declarationcorresponding to is a function parameter pack, then the type of its declarator-id is compared with each remaining parameter type in the parameter-type-list of A.
Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack.
During partial ordering, if was originally a function parameter pack:
- if P does not contain a function parameter type corresponding to then is ignored;
- otherwise, if is not a function parameter pack, template argument deduction fails.
[Example 6: template<class T, class... U> void f(T*, U...) { } template<class T> void f(T) { } template void f(int*); — _end example_]
These forms can be used in the same way asTis for further composition of types.
[Example 7:
X<int> (*)(char[6]) is of the formtemplate-name<T> (*)(type_[i]) which is a variant of_type (*)(T) where type isX<int>andTischar[6].
— _end example_]
Template arguments cannot be deduced from function arguments involving constructs other than the ones specified above.
When the value of the argument corresponding to a constant template parameter Pthat is declared with a dependent type is deduced from an expression, the template parameters in the type of Pare deduced from the type of the value.
[Example 8: template<long n> struct A { };template<typename T> struct C;template<typename T, T n> struct C<A<n>> { using Q = T;};using R = long;using R = C<A<2>>::Q; — _end example_]
The type of N in the type T[N] is std::size_t.
[Example 9: template<typename T> struct S;template<typename T, T n> struct S<int[n]> { using Q = T;};using V = decltype(sizeof 0);using V = S<int[42]>::Q; — _end example_]
The type of B in the noexcept-specifier noexcept(B) of a function type is bool.
[Example 10: template<bool> struct A { };template<auto> struct B;template<auto X, void (*F)() noexcept(X)> struct B<F> { A<X> ax;};void f_nothrow() noexcept; B<f_nothrow> bn; — _end example_]
[Example 11: template<class T, T i> void f(int (&a)[i]);int v[10];void g() { f(v); } — _end example_]
[Note 5:
Except for reference and pointer types, a major array bound is not part of a function parameter type and cannot be deduced from an argument:template<int i> void f1(int a[10][i]);template<int i> void f2(int a[i][20]);template<int i> void f3(int (&a)[i][20]);void g() { int v[10][20]; f1(v); f1<20>(v); f2(v); f2<10>(v); f3(v); }
— _end note_]
[Note 6:
If, in the declaration of a function template with a constant template parameter, the constant template parameter is used in a subexpression in the function parameter list, the expression is a non-deduced context as specified above.
[Example 12: template <int i> class A { };template <int i> void g(A<i+1>);template <int i> void f(A<i>, A<i+1>);void k() { A<1> a1; A<2> a2; g(a1); g<0>(a1); f(a1, a2); } — _end example_]
— _end note_]
[Note 7:
Template parameters do not participate in template argument deduction if they are used only in non-deduced contexts.
For example,
template<int i, typename T>T deduce(typename A<T>::X x, T t, typename B<i>::Y y); A<int> a; B<77> b;int x = deduce<77>(a.xm, 62, b.ym); — _end note_]
If P has a form that contains <i>, and if the type of i differs from the type of the corresponding template parameter of the template named by the enclosing simple-template-id, deduction fails.
If P has a form that contains [i], and if the type ofi is not an integral type, deduction fails.120
If P has a form that includes noexcept(i) and the type of i is not bool, deduction fails.
[Example 13: template<int i> class A { };template<short s> void f(A<s>);void k1() { A<1> a; f(a); f<1>(a); } template<const short cs> class B { };template<short s> void g(B<s>);void k2() { B<1> b; g(b); } — _end example_]
Atemplate-argumentcan be deduced from a function, pointer to function, or pointer-to-member-function type.
[Example 14: template<class T> void f(void(*)(T,int));template<class T> void foo(T,int);void g(int,int);void g(char,int);void h(int,int,int);void h(char,int);int m() { f(&g); f(&h); f(&foo); } — _end example_]
A templatetype-parametercannot be deduced from the type of a function default argument.
[Example 15: template <class T> void f(T = 5, T = 7);void g() { f(1); f(); f<int>(); } — _end example_]
Thetemplate-argumentcorresponding to a template template parameter is deduced from the type of thetemplate-argumentof a class template specialization used in the argument list of a function call.
[Example 16: template <template <class T> class X> struct A { };template <template <class T> class X> void f(A<X>) { } template<class T> struct B { }; A<B> ab; f(ab); — _end example_]
[Note 8:
Template argument deduction involving parameter packs ([temp.variadic]) can deduce zero or more arguments for each parameter pack.
— _end note_]
[Example 17: template<class> struct X { };template<class R, class ... ArgTypes> struct X<R(int, ArgTypes ...)> { };template<class ... Types> struct Y { };template<class T, class ... Types> struct Y<T, Types& ...> { };template<class ... Types> int f(void (*)(Types ...));void g(int, float); X<int> x1; X<int(int, float, double)> x2; X<int(float, int)> x3; Y<> y1; Y<int&, float&, double&> y2; Y<int, float, double> y3; int fv = f(g); — _end example_]
13.10.3.7 Deducing template arguments from a function declaration [temp.deduct.decl]
In a declaration whose declarator-id refers to a specialization of a function template, template argument deduction is performed to identify the specialization to which the declaration refers.
In all these cases, P is the type of the function template being considered as a potential match and A is either the function type from the declaration or the type of the deallocation function that would match the placementoperator new as described in [expr.new].
The deduction is done as described in [temp.deduct.type].
If, for the set of function templates so considered, there is either no match or more than one match after partial ordering has been considered ([temp.func.order]), deduction fails and, in the declaration cases, the program is ill-formed.