13 Templates [temp]

13.10 Function template specializations [temp.fct.spec]

13.10.3 Template argument deduction [temp.deduct] 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 it P) is compared with an actual type (call it A), and an attempt is made to find template argument values (a type for a type parameter, a value for a non-type parameter, or a template for a template parameter) that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.
In some cases, the deduction is done using a single set of types P and A, in other cases, there will be a set of corresponding types P and A.
Type deduction is done independently for each P/A pair, and the deduced template argument values are then combined.
If type deduction cannot be done for any P/A pair, 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 type P can be composed from a number of other types, templates, and non-type 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 non-type 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 non-type values that are used to compose P participate 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 A need not have the same form.
— end note]
The non-deduced contexts are:
  • The nested-name-specifier of a type that was specified using a qualified-id.
  • A non-type 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 ([over.over]), and one or more of the following apply:
    • more than one function matches the function parameter type (resulting in an ambiguous deduction), or
    • no function matches the function parameter type, or
    • the overload set supplied as an argument contains one or more function templates.
  • 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}); // error: no argument deduced for T — end example]
  • A function parameter pack that does not occur at the end of the parameter-declaration-list.
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 as A<T>​::​B<T2>, both T and T2 are non-deduced.
Likewise, if a type is specified as A<I+J>​::​X<T>, I, J, and T are non-deduced.
If a type is specified as void f(typename A<T>​::​B, A<T>), the T in A<T>​::​B is non-deduced but the T in A<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); // error: T deduced as both A and B f(b,a); // error: T deduced as both A and B f(a,a); // OK, T is A f(b,b); // OK, T is 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); // OK, T is int and U is float f(g2); // error: T deduced as both char and int f(g3); // error: U deduced as both char and float }
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); // OK, E is false f1(g2); // OK, E is true f2(g3); // error: B deduced as both true and false }
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); // f(const int*) }
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); // calls f(B<int>&) f(d2); // calls f(B<int>&) }
— end example]
A template type argument T, a template template argument TT, or a template non-type argument i can be deduced if P and A have 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<> 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 2: 
If a type matches such a form but contains no Ts, is, or TTs, deduction is not possible.
— end note]
Similarly, <T> represents template argument lists where at least one argument contains a T, <i> represents template argument lists where at least one argument contains an i and <> represents template argument lists where no argument contains a T or an i.
If P has a form that contains <T> or <i>, 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; // #1 template<class T1, class... Z> class S<T1, const Z&...> { }; // #2 template<class T1, class T2> class S<T1, const T2&> { }; // #3 S<int, const int&> s; // both #2 and #3 match; #3 is more specialized template<class T, class... U> struct A { }; // #1 template<class T1, class T2, class... U> struct A<T1, T2*, U...> { }; // #2 template<class T1, class T2> struct A<T1, T2> { }; // #3 template struct A<int, int*>; // selects #2 — end example]
Similarly, if P has a form that contains (T), then each parameter type of the respective parameter-type-list ([dcl.fct]) of P 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 3: 
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&) { } // #1 template <> void f(int&&) { } // #2 void g(int i) { f(i); // calls f<int&>(int&), i.e., #1 f(0); // calls f<int>(int&&), i.e., #2 } — end example]
If the parameter-declaration corresponding 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...) { } // #1 template<class T> void f(T) { } // #2 template void f(int*); // selects #1 — end example]
These forms can be used in the same way as T is for further composition of types.
[Example 7: 
X<int> (*)(char[6]) is of the form template-name<T> (*)(type[i]) which is a variant of type (*)(T) where type is X<int> and T is char[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 non-type template parameter P that is declared with a dependent type is deduced from an expression, the template parameters in the type of P are 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; // OK; T was deduced as long from the // template argument value in the type A<2> — 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; // OK; T was deduced as std​::​size_t from the type int[42] — 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; // OK, type of X deduced as bool — end example]
[Example 11: template<class T, T i> void f(int (&a)[i]); int v[10]; void g() { f(v); // OK, T is std​::​size_t } — end example]
[Note 4: 
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); // OK, i deduced as 20 f1<20>(v); // OK f2(v); // error: cannot deduce template-argument i f2<10>(v); // OK f3(v); // OK, i deduced as 10 }
— end note]
[Note 5: 
If, in the declaration of a function template with a non-type template parameter, the non-type 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); // error: deduction fails for expression i+1 g<0>(a1); // OK f(a1, a2); // OK } — end example]
— end note]
[Note 6: 
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 is not deduced here T t, // but T is deduced here typename B<i>::Y y); // i is not deduced here A<int> a; B<77> b; int x = deduce<77>(a.xm, 62, b.ym); // T deduced as int; a.xm must be convertible to A<int>​::​X // i is explicitly specified to be 77; b.ym must be convertible to B<77>​::​Y — 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 of i is not an integral type, deduction fails.124
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); // error: deduction fails for conversion from int to short f<1>(a); // OK } template<const short cs> class B { }; template<short s> void g(B<s>); void k2() { B<1> b; g(b); // OK, cv-qualifiers are ignored on template parameter types } — end example]
A template-argument can 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); // error: ambiguous f(&h); // OK, void h(char,int) is a unique match f(&foo); // error: type deduction fails because foo is a template } — end example]
A template type-parameter cannot 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); // OK, calls f<int>(1,7) f(); // error: cannot deduce T f<int>(); // OK, calls f<int>(5,7) } — end example]
The template-argument corresponding to a template template-parameter is deduced from the type of the template-argument of 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); // calls f(A<B>) — end example]
[Note 7: 
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; // uses primary template X<int(int, float, double)> x2; // uses partial specialization; ArgTypes contains float, double X<int(float, int)> x3; // uses primary template Y<> y1; // uses primary template; Types is empty Y<int&, float&, double&> y2; // uses partial specialization; T is int&, Types contains float, double Y<int, float, double> y3; // uses primary template; Types contains int, float, double int fv = f(g); // OK; Types contains int, float — end example]
Although the template-argument corresponding to a template-parameter of type bool can be deduced from an array bound, the resulting value will always be true because the array bound will be nonzero.