[temp.deduct.general] (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:

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