14 Templates [temp]

14.8 Function template specializations [temp.fct.spec]

14.8.2 Template argument deduction [temp.deduct]

14.8.2.5 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.

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 and the return type.

  • 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 the value so determined must be 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:

  • The nested-name-specifier of a type that was specified using a qualified-id.

  • The expression of a decltype-specifier.

  • 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 argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions ([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 set of functions 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 std::initializer_list or reference to possibly cv-qualified std::initializer_list type. [ Example:

    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: 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: 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 could be A or B
  f(b,a);           // error: T could be A or 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 could be char or int
  f(g3);            // error: U could be char or float
}

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:

T
cv-list T
T*
T&
T&&
T[integer-constant]
template-name<T>  (where template-name refers to a class template)
type(T)
T()
T(T)
T type::*
type T::*
T T::*
T (type::*)()
type (T::*)()
type (type::*)(T)
type (T::*)(T)
T (type::*)(T)
T (T::*)()
T (T::*)(T)
type[i]
template-name<i>  (where template-name refers to a class template)
TT<T>
TT<i>
TT<>

where (T) represents a parameter-type-list where at least one parameter type contains a T, and () represents a parameter-type-list where no parameter type contains a T. 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 Pi of the respective template argument list P is compared with the corresponding argument Ai 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 Pi is a pack expansion, then the pattern of Pi 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 Pi. During partial ordering ([temp.deduct.partial]), if Ai was originally a pack expansion:

  • if P does not contain a template argument corresponding to Ai then Ai is ignored;

  • otherwise, if Pi is not a pack expansion, template argument deduction fails.

Example:

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 Pi of the respective parameter-type-list of P is compared with the corresponding parameter type Ai 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 Pi and Ai are parameters of the top-level parameter-type-list of P and A, respectively, Pi is adjusted if it is an rvalue reference to a cv-unqualified template parameter and Ai is an lvalue reference, in which case the type of Pi is changed to be the template parameter type (i.e., T&& is changed to simply T). [ Note: As a result, when Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be deduced as X&.  — end note ] [ Example:

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 Pi 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 ([temp.deduct.partial]), if Ai was originally a function parameter pack:

  • if P does not contain a function parameter type corresponding to Ai then Ai is ignored;

  • otherwise, if Pi is not a function parameter pack, template argument deduction fails.

Example:

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:

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.

A template type argument cannot be deduced from the type of a non-type template-argument.

Example:

template<class T, T i> void f(double a[10][i]);
int v[10][20];
f(v);               // error: argument for template-parameter T cannot be deduced

 — end example ]

Note: 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 to be 20
  f1<20>(v);        // OK
  f2(v);            // error: cannot deduce template-argument i
  f2<10>(v);        // OK
  f3(v);            // OK: i deduced to be 10
}

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:

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: 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 is deduced to be 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 the corresponding value of A differs from the type of i, deduction fails. If P has a form that contains [i], and if the type of i is not an integral type, deduction fails.144Example:

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:

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:

template <class T> void f(T = 5, T = 7);
void g() {
  f(1);             // OK: call f<int>(1,7)
  f();              // error: cannot deduce T
  f<int>();         // OK: call 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:

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: Template argument deduction involving parameter packs ([temp.variadic]) can deduce zero or more arguments for each parameter pack.  — end note ][ Example:

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;                         // use 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 may be deduced from an array bound, the resulting value will always be true because the array bound will be non-zero.