[temp.deduct.type] (original) (raw)

13 Templates [temp]

13.10 Function template specializations [temp.fct.spec]

13.10.3 Template argument deduction [temp.deduct]

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 non-type parameter, or a template for a 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 non-type values:

In most cases, the types, templates, and non-type 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.

The non-deduced contexts are:

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 template type argumentT, a template template argumentTT, or a template non-type 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<> where

[Note 2:

If a type matches such a form but contains noTs, is, or TTs, deduction is not possible.

— _end note_]

Similarly,<T>represents template argument lists where at least one argument contains aT,<i>represents template argument lists where at least one argument contains aniand<>represents template argument lists where no argument contains aTor ani.

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:

[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 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&) { } 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:

[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 non-type 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 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); f1<20>(v); f2(v); f2<10>(v); f3(v); }

— _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); g<0>(a1); f(a1, a2); } — _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 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.123

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_]

[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 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; 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_]