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

209 lines
12 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.call]
# 13 Templates [[temp]](./#temp)
## 13.10 Function template specializations [[temp.fct.spec]](temp.fct.spec#temp.deduct.call)
### 13.10.3 Template argument deduction [[temp.deduct]](temp.deduct#call)
#### 13.10.3.2 Deducing template arguments from a function call [temp.deduct.call]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8146)
Template argument deduction is done by comparing each function
template parameter type (call itP)
that contains template parameters that participate in template argument deduction
with the type of the corresponding argument of the call (call itA)
as described below[.](#1.sentence-1)
If removing references and cv-qualifiers from P givesstd::initializer_list<€²> or P′[N] for some P′ and N and the
argument is a non-empty initializer list ([[dcl.init.list]](dcl.init.list "9.5.5List-initialization")), then deduction is
performed instead for each element of the initializer list independently,
taking P′ as separate function template parameter types P′i and the ith initializer element as the corresponding argument[.](#1.sentence-2)
In the P′[N] case, if N is a constant template parameter,N is deduced from the length of the initializer list[.](#1.sentence-3)
Otherwise, an initializer list argument causes the
parameter to be considered a non-deduced context ([[temp.deduct.type]](temp.deduct.type "13.10.3.6Deducing template arguments from a type"))[.](#1.sentence-4)
[*Example [1](#example-1)*: template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced as int f({1,"asdf"}); // error: T deduced as both int and const char*template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for Ttemplate<class T, int N> void h(T const(&)[N]);
h({1,2,3}); // T deduced as int; N deduced as 3template<class T> void j(T const(&)[3]);
j({42}); // T deduced as int; array bound not consideredstruct Aggr { int i; int j; };template<int N> void k(Aggr const(&)[N]);
k({1,2,3}); // error: deduction fails, no conversion from int to Aggr k({{1},{2},{3}}); // OK, N deduced as 3template<int M, int N> void m(int const(&)[M][N]);
m({{1,2},{3,4}}); // M and N both deduced as 2template<class T, int N> void n(T const(&)[N], T);
n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3template<typename T, int N> void o(T (* const (&)[N])(T)) { }int f1(int);int f4(int);char f4(char);
o({ &f1, &f4 }); // OK, T deduced as int from first element, nothing// deduced from second element, N deduced as 2 o({ &f1, static_cast<char(*)(char)>(&f4) }); // error: conflicting deductions for T — *end example*]
For a function parameter pack that occurs at the end
of the [*parameter-declaration-list*](dcl.fct#nt:parameter-declaration-list "9.3.4.6Functions[dcl.fct]"),
deduction is performed for each remaining argument of the call,
taking the type P of the [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1General[dcl.decl.general]") of the function parameter pack
as the corresponding function template parameter type[.](#1.sentence-5)
Each deduction deduces template arguments for subsequent positions in
the template parameter packs expanded by the function parameter pack[.](#1.sentence-6)
When a function parameter pack appears in a non-deduced
context ([[temp.deduct.type]](temp.deduct.type "13.10.3.6Deducing template arguments from a type")), the type of that pack is
never deduced[.](#1.sentence-7)
[*Example [2](#example-2)*: template<class ... Types> void f(Types& ...);template<class T1, class ... Types> void g(T1, Types ...);template<class T1, class ... Types> void g1(Types ..., T1);
void h(int x, float& y) {const int z = x;
f(x, y, z); // Types deduced as int, float, const int g(x, y, z); // T1 deduced as int; Types deduced as float, int g1(x, y, z); // error: Types is not deduced g1<int, int, int>(x, y, z); // OK, no deduction occurs} — *end example*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8229)
IfP is not a reference type:
- [(2.1)](#2.1)
IfA is an array type, the pointer type produced by the [array-to-pointer
standard conversion](conv.array "7.3.3Array-to-pointer conversion[conv.array]") is used in place ofA for type deduction;
otherwise,
- [(2.2)](#2.2)
IfA is a function type, the pointer type produced by the[function-to-pointer standard conversion](conv.func "7.3.4Function-to-pointer conversion[conv.func]") is used in place
ofA for type
deduction; otherwise,
- [(2.3)](#2.3)
IfA is a cv-qualified type, the top-level cv-qualifiers ofA's
type are ignored for type deduction[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8259)
IfP is a cv-qualified type, the top-level cv-qualifiers ofP's
type are ignored for type deduction[.](#3.sentence-1)
IfP is a reference type, the type
referred to byP is used for type deduction[.](#3.sentence-2)
[*Example [3](#example-3)*: template<class T> int f(const T&);int n1 = f(5); // calls f<int>(const int&)const int i = 0;int n2 = f(i); // calls f<int>(const int&)template <class T> int g(volatile T&);int n3 = g(i); // calls g<const int>(const volatile int&) — *end example*]
A [*forwarding reference*](#def:forwarding_reference "13.10.3.2Deducing template arguments from a function call[temp.deduct.call]") is an rvalue reference to a cv-unqualified template parameter
that does not represent a template parameter of a class template
(during class template argument deduction ([[over.match.class.deduct]](over.match.class.deduct "12.2.2.9Class template argument deduction")))[.](#3.sentence-3)
If P is a forwarding reference and the argument is an
lvalue, the type “lvalue reference to A” is used in place of A for type
deduction[.](#3.sentence-4)
[*Example [4](#example-4)*: template <class T> int f(T&& heisenreference);template <class T> int g(const T&&);int i;int n1 = f(i); // calls f<int&>(int&)int n2 = f(0); // calls f<int>(int&&)int n3 = g(i); // error: would call g<int>(const int&&), which// would bind an rvalue reference to an lvaluetemplate <class T> struct A {template <class U> A(T&&, U&&, int*); // #1: T&& is not a forwarding reference.// U&& is a forwarding reference. A(T&&, int*); // #2};
template <class T> A(T&&, int*) -> A<T>; // #3: T&& is a forwarding reference.int *ip;
A a{i, 0, ip}; // error: cannot deduce from #1 A a0{0, 0, ip}; // uses #1 to deduce A<int> and #1 to initialize A a2{i, ip}; // uses #3 to deduce A<int&> and #2 to initialize — *end example*]
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8315)
In general, the deduction process attempts to find template argument
values that will make the deducedA identical toA (after
the typeA is transformed as described above)[.](#4.sentence-1)
However, there are
three cases that allow a difference:
- [(4.1)](#4.1)
If the originalP is a reference type, the deducedA (i.e.,
the type referred to by the reference) can be more cv-qualified than
the transformed A[.](#4.1.sentence-1)
- [(4.2)](#4.2)
The transformed A can be another pointer or pointer-to-member type that can be converted
to the deducedA via a [function pointer conversion](conv.fctptr "7.3.14Function pointer conversions[conv.fctptr]") and/or[qualification conversion](conv.qual "7.3.6Qualification conversions[conv.qual]")[.](#4.2.sentence-1)
- [(4.3)](#4.3)
IfP is a class andP has the form[*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") ortypenameopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]"),
then
the transformed A can be a derived class D of the
deducedA[.](#4.3.sentence-1)
Likewise, ifP is a pointer to a class of the form[*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") ortypenameopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]"),
the transformed A can be a pointer to a
derived class D of the class pointed to by the deducedA[.](#4.3.sentence-2)
However, if there is a class C that is
a (direct or indirect) base class of D and
derived (directly or indirectly) from a class B and
that would be a valid deduced A,
the deduced A cannot be B or pointer to B,
respectively[.](#4.3.sentence-3)
[*Example [5](#example-5)*: template <typename... T> struct X;template <> struct X<> {};template <typename T, typename... Ts>struct X<T, Ts...> : X<Ts...> {};struct D : X<int> {};struct E : X<>, X<int> {};
template <typename... T>int f(const X<T...>&);int x = f(D()); // calls f<int>, not f<>// B is X<>, C is X<int>int z = f(E()); // calls f<int>, not f<> — *end example*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8390)
These alternatives are considered only if type deduction would
otherwise fail[.](#5.sentence-1)
If they yield more than one possible deducedA,
the type deduction fails[.](#5.sentence-2)
[*Note [1](#note-1)*:
If a template parameter
is not used in any of the function parameters of a function template,
or is used only in a non-deduced context, its corresponding[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") cannot be deduced from a function call and the[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") must be explicitly specified[.](#5.sentence-3)
— *end note*]
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8406)
WhenP is a function type, function pointer type, or pointer-to-member-function type:
- [(6.1)](#6.1)
If the argument is an overload set containing one or more function templates,
the parameter is treated as a non-deduced context[.](#6.1.sentence-1)
- [(6.2)](#6.2)
If the argument is an overload set (not containing function templates), trial
argument deduction is attempted using each of the members of the set
whose associated constraints ([[temp.constr.constr]](temp.constr.constr "13.5.2Constraints")) are satisfied[.](#6.2.sentence-1)
If all successful deductions yield the same deduced A,
that deduced A is the result of deduction;
otherwise, the parameter is treated as a non-deduced context[.](#6.2.sentence-2)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8423)
[*Example [6](#example-6)*: // Only one function of an overload set matches the call so the function parameter is a deduced context.template <class T> int f(T (*p)(T));int g(int);int g(char);int i = f(g); // calls f(int (*)(int)) — *end example*]
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8434)
[*Example [7](#example-7)*: // Ambiguous deduction causes the second function parameter to be a non-deduced context.template <class T> int f(T, T (*p)(T));int g(int);char g(char);int i = f(1, g); // calls f(int, int (*)(int)) — *end example*]
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8445)
[*Example [8](#example-8)*: // The overload set contains a template, causing the second function parameter to be a non-deduced context.template <class T> int f(T, T (*p)(T));char g(char);template <class T> T g(T);int i = f(1, g); // calls f(int, int (*)(int)) — *end example*]
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L8456)
[*Example [9](#example-9)*: // All arguments for placeholder type deduction ([[dcl.type.auto.deduct]](dcl.type.auto.deduct "9.2.9.7.2Placeholder type deduction")) yield the same deduced type.template<bool B> struct X {static void f(short) requires B; // #1static void f(short); // #2};void test() {auto x = &X<true>::f; // OK, deduces void(*)(short), selects #1auto y = &X<false>::f; // OK, deduces void(*)(short), selects #2} — *end example*]