Files
2025-10-25 03:02:53 +03:00

369 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[temp.deduct.general]
# 13 Templates [[temp]](./#temp)
## 13.10 Function template specializations [[temp.fct.spec]](temp.fct.spec#temp.deduct.general)
### 13.10.3 Template argument deduction [[temp.deduct]](temp.deduct#general)
#### 13.10.3.1 General [temp.deduct.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L7733)
When a
function template
specialization is referenced, all of the
template arguments shall have values[.](#1.sentence-1)
The values can be
explicitly specified or, in some cases, be deduced from the use
or obtained from default[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]")*s*[.](#1.sentence-2)
[*Example [1](#example-1)*:
void f(Array<dcomplex>& cv, Array<int>& ci) { sort(cv); // calls sort(Array<dcomplex>&) sort(ci); // calls sort(Array<int>&)} andvoid g(double d) {int i = convert<int>(d); // calls convert<int,double>(double)int c = convert<char>(d); // calls convert<char,double>(double)}
— *end example*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L7758)
When an explicit template argument list is specified, if the
given [*template-id*](temp.names#nt:template-id "13.3Names of template specializations[temp.names]") or[*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]") is not valid ([[temp.names]](temp.names "13.3Names of template specializations")),
type deduction fails[.](#2.sentence-1)
Otherwise, the specified template argument values are substituted for the
corresponding template parameters as specified below[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L7766)
After this substitution is performed, the function parameter type
adjustments described in [[dcl.fct]](dcl.fct "9.3.4.6Functions") are performed[.](#3.sentence-1)
[*Example [2](#example-2)*:
A parameter type of “void (const int, int[5])” becomes
“void(*)(int,int*)”[.](#3.sentence-2)
— *end example*]
[*Note [1](#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[.](#3.sentence-3)
— *end note*]
[*Example [3](#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() {// #1: function type is f(int), t is non const f<int>(1); // #2: function type is f(int), t is const f<const int>(1); // #3: function type is g(int), x is const g<int>(1); // #4: function type is g(int), x is const g<const int>(1); // #5: function type is h(int, const int*) h<const int>(1,0);} — *end example*]
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L7803)
[*Note [2](#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[.](#4.sentence-1)
— *end note*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L7809)
The resulting substituted and adjusted function type is used as
the type of the function template for template argument
deduction[.](#5.sentence-1)
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[.](#5.sentence-2)
If the substitution results in an invalid type,
as described above, type deduction fails[.](#5.sentence-3)
[*Example [4](#example-4)*: template <class T, class U = double>void f(T t = 0, U u = 0);
void g() { f(1, 'c'); // f<int,char>(1,'c') f(1); // f<int,double>(1,0) f(); // error: T cannot be deduced f<int>(); // f<int,double>(0,0) f<int,char>(); // f<int,char>(0,0)} — *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[.](#5.sentence-4)
If the substitution results in an
invalid type, as described above, type deduction fails[.](#5.sentence-5)
If the function template has associated constraints ([[temp.constr.decl]](temp.constr.decl "13.5.3Constrained declarations")),
those constraints are checked for satisfaction ([[temp.constr.constr]](temp.constr.constr "13.5.2Constraints"))[.](#5.sentence-6)
If the constraints are not satisfied, type deduction fails[.](#5.sentence-7)
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[.](#5.sentence-8)
[*Note [3](#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[.](#5.sentence-9)
— *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[.](#5.sentence-10)
If the substitution results in an invalid type, as described above,
type deduction fails[.](#5.sentence-11)
[*Example [5](#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); // #1template <class T> void f(int, T); // #2struct A {} a;struct ZZ {template <class T, class = typename Z<T>::xx> operator T *(); operator int();};int main() { ZZ zz;
f(1, a); // OK, deduction fails for #1 because there is no conversion from int to void* f(zz, 42); // OK, deduction fails for #1 because C<int> is not satisfied} — *end example*]
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L7882)
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[.](#6.sentence-1)
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[.](#6.sentence-2)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L7891)
The [*deduction substitution loci*](#def:deduction_substitution_loci "13.10.3.1General[temp.deduct.general]") are
- [(7.1)](#7.1)
the function type outside of the [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5Exception specifications[except.spec]"),
- [(7.2)](#7.2)
the [*explicit-specifier*](dcl.fct.spec#nt:explicit-specifier "9.2.3Function specifiers[dcl.fct.spec]"),
- [(7.3)](#7.3)
the template parameter declarations, and
- [(7.4)](#7.4)
the template argument list of a partial specialization ([[temp.spec.partial.general]](temp.spec.partial.general "13.7.6.1General"))[.](#7.sentence-1)
The substitution occurs in all types and expressions that are used
in the deduction substitution loci[.](#7.sentence-2)
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[.](#7.sentence-3)
The substitution proceeds in lexical order and stops when
a condition that causes deduction to fail is encountered[.](#7.sentence-4)
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[.](#7.sentence-5)
[*Note [4](#note-4)*:
The equivalent substitution in
exception specifications ([[except.spec]](except.spec "14.5Exception specifications"))
and function contract assertions ([[dcl.contract.func]](dcl.contract.func "9.4.1General"))
is done only when
the [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5Exception specifications[except.spec]") or [*function-contract-specifier*](dcl.contract.func#nt:function-contract-specifier "9.4.1General[dcl.contract.func]"), respectively,
is instantiated,
at which point a program is ill-formed
if the substitution results in an invalid type or expression[.](#7.sentence-6)
— *end note*]
[*Example [6](#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; // redeclarationtemplate <class T> void h(...) { }void x() { f<int>(0); // OK, substituting return type causes deduction to fail g<int>(0); // error, substituting parameter type instantiates A<int> h<int>(0); // ill-formed, no diagnostic required} — *end example*]
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L7941)
If a substitution results in an invalid type or expression, type deduction fails[.](#8.sentence-1)
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[.](#8.sentence-2)
[*Note [5](#note-5)*:
If no diagnostic is required, the program is still ill-formed[.](#8.sentence-3)
Access checking is done as part of the substitution process[.](#8.sentence-4)
— *end note*]
Invalid types and expressions can result in a deduction failure
only in the immediate context of the deduction substitution loci[.](#8.sentence-5)
[*Note [6](#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[.](#8.sentence-6)
Such effects are not in the “immediate context” and can result in the
program being ill-formed[.](#8.sentence-7)
— *end note*]
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L7959)
When substituting into a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]"),
substitution into its body is not in the immediate context[.](#9.sentence-1)
[*Note [7](#note-7)*:
The intent is to avoid requiring implementations to deal with
substitution failure involving arbitrary statements[.](#9.sentence-2)
[*Example [7](#example-7)*: template <class T>auto f(T) -> decltype([]() { T::invalid; } ());void f(...);
f(0); // error: invalid expression not part of the immediate contexttemplate <class T, std::size_t = sizeof([]() { T::invalid; })>void g(T);void g(...);
g(0); // error: invalid expression not part of the immediate contexttemplate <class T>auto h(T) -> decltype([x = T::invalid]() { });void h(...);
h(0); // error: invalid expression not part of the immediate contexttemplate <class T>auto i(T) -> decltype([]() -> typename T::invalid { });void i(...);
i(0); // error: invalid expression not part of the immediate contexttemplate <class T>auto j(T t) -> decltype([](auto x) -> decltype(x.invalid) { } (t)); // #1void j(...); // #2 j(0); // deduction fails on #1, calls #2 — *end example*]
— *end note*]
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L7995)
[*Example [8](#example-8)*: struct X { };struct Y { Y(X) {}};
template <class T> auto f(T t1, T t2) -> decltype(t1 + t2); // #1 X f(Y, Y); // #2 X x1, x2;
X x3 = f(x1, x2); // deduction fails on #1 (cannot add X+X), calls #2 — *end example*]
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8011)
[*Note [8](#note-8)*:
Type deduction can fail for the following reasons:
- [(11.1)](#11.1)
Attempting to instantiate a pack expansion containing multiple packs of differing lengths[.](#11.1.sentence-1)
- [(11.2)](#11.2)
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[.](#11.2.sentence-1)
[*Example [9](#example-9)*: template <class T> int f(T[5]);int I = f<int>(0);int j = f<void>(0); // invalid array — *end example*]
- [(11.3)](#11.3)
Attempting to use a type that is not a class or enumeration type in a qualified name[.](#11.3.sentence-1)
[*Example [10](#example-10)*: template <class T> int f(typename T::B*);int i = f<int>(0); — *end example*]
- [(11.4)](#11.4)
Attempting to use a type in a [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]") of a[*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3Qualified names[expr.prim.id.qual]") when
that type does not contain the specified member, or
* [(11.4.1)](#11.4.1)
the specified member is not a type where a type is required, or
* [(11.4.2)](#11.4.2)
the specified member is not a template where a template is required, or
* [(11.4.3)](#11.4.3)
the specified member is not a non-type, non-template where a non-type,
non-template is required[.](#11.4.sentence-1)
[*Example [11](#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() {// Deduction fails in each of these cases: f<A>(0); // A does not contain a member Y f<B>(0); // The Y member of B is not a type g<C>(0); // The N member of C is not a non-type, non-template name h<D>(0); // The TT member of D is not a template} — *end example*]
- [(11.5)](#11.5)
Attempting to create a pointer to reference type[.](#11.5.sentence-1)
- [(11.6)](#11.6)
Attempting to create a reference to void[.](#11.6.sentence-1)
- [(11.7)](#11.7)
Attempting to create “pointer to member of T” when T is not a
class type[.](#11.7.sentence-1)
[*Example [12](#example-12)*: template <class T> int f(int T::*);int i = f<int>(0); — *end example*]
- [(11.8)](#11.8)
Attempting to give an invalid type to a constant template parameter[.](#11.8.sentence-1)
[*Example [13](#example-13)*: template <class T, T> struct S {};template <class T> int f(S<T, T{}>*); // #1class X {int m;};int i0 = f<X>(0); // #1 uses a value of non-structural type X as a constant template argument — *end example*]
- [(11.9)](#11.9)
Attempting to perform an invalid conversion in either a template
argument expression, or an expression used in the function
declaration[.](#11.9.sentence-1)
[*Example [14](#example-14)*: template <class T, T*> int f(int);int i2 = f<int,1>(0); // can't convert 1 to int* — *end example*]
- [(11.10)](#11.10)
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[.](#11.10.sentence-1)
- [(11.11)](#11.11)
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]](expr.prim.lambda.closure "7.5.6.2Closure types"))[.](#11.11.sentence-1)
— *end note*]
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8124)
[*Example [15](#example-15)*:
In the following example,
assuming a signed char cannot represent the value 1000,
a [narrowing conversion](dcl.init.list#def:conversion,narrowing "9.5.5List-initialization[dcl.init.list]") would be required
to convert the [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") of type int to signed char,
therefore substitution fails for the
second template ([[temp.arg.nontype]](temp.arg.nontype "13.4.3Constant template arguments"))[.](#12.sentence-1)
template <int> int f(int);template <signed char> int f(int);int i1 = f<1000>(0); // OKint i2 = f<1>(0); // ambiguous; not narrowing — *end example*]