[temp.deduct.call] (original) (raw)
13 Templates [temp]
13.10 Function template specializations [temp.fct.spec]
13.10.3 Template argument deduction [temp.deduct]
13.10.3.2 Deducing template arguments from a function call [temp.deduct.call]
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.
If removing references and cv-qualifiers from P givesor for some and N and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list independently, taking as separate function template parameter types and the initializer element as the corresponding argument.
In the case, if N is a constant template parameter,N is deduced from the length of the initializer list.
Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context ([temp.deduct.type]).
[Example 1: template<class T> void f(std::initializer_list<T>); f({1,2,3}); f({1,"asdf"}); template<class T> void g(T); g({1,2,3}); template<class T, int N> void h(T const(&)[N]); h({1,2,3}); template<class T> void j(T const(&)[3]); j({42}); struct Aggr { int i; int j; };template<int N> void k(Aggr const(&)[N]); k({1,2,3}); k({{1},{2},{3}}); template<int M, int N> void m(int const(&)[M][N]); m({{1,2},{3,4}}); template<class T, int N> void n(T const(&)[N], T); n({{1},{2},{3}},Aggr()); template<typename T, int N> void o(T (* const (&)[N])(T)) { } int f1(int);int f4(int);char f4(char); o({ &f1, &f4 }); o({ &f1, static_cast<char(*)(char)>(&f4) }); — _end example_]
For a function parameter pack that occurs at the end of the parameter-declaration-list, deduction is performed for each remaining argument of the call, taking the type Pof the declarator-id of the function parameter pack as the corresponding function template parameter type.
Each deduction deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack.
When a function parameter pack appears in a non-deduced context ([temp.deduct.type]), the type of that pack is never deduced.
[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); g(x, y, z); g1(x, y, z); g1<int, int, int>(x, y, z); } — _end example_]
IfPis not a reference type:
- IfAis an array type, the pointer type produced by the array-to-pointer standard conversion is used in place ofAfor type deduction; otherwise,
- IfAis a function type, the pointer type produced by thefunction-to-pointer standard conversion is used in place ofAfor type deduction; otherwise,
- IfAis a cv-qualified type, the top-level cv-qualifiers ofA's type are ignored for type deduction.
IfPis a cv-qualified type, the top-level cv-qualifiers ofP's type are ignored for type deduction.
IfPis a reference type, the type referred to byPis used for type deduction.
[Example 3: template<class T> int f(const T&);int n1 = f(5); const int i = 0;int n2 = f(i); template <class T> int g(volatile T&);int n3 = g(i); — _end example_]
A forwarding referenceis 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])).
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.
[Example 4: template <class T> int f(T&& heisenreference);template <class T> int g(const T&&);int i;int n1 = f(i); int n2 = f(0); int n3 = g(i); template <class T> struct A { template <class U> A(T&&, U&&, int*); A(T&&, int*); };template <class T> A(T&&, int*) -> A<T>; int *ip; A a{i, 0, ip}; A a0{0, 0, ip}; A a2{i, ip}; — _end example_]
In general, the deduction process attempts to find template argument values that will make the deducedAidentical toA(after the typeAis transformed as described above).
However, there are three cases that allow a difference:
- If the originalPis a reference type, the deducedA(i.e., the type referred to by the reference) can be more cv-qualified than the transformed A.
- IfPis a class andPhas the formsimple-template-id, then the transformed Acan be a derived class D of the deducedA.
Likewise, ifPis a pointer to a class of the formsimple-template-id, the transformed Acan be a pointer to a derived class D pointed to by the deducedA.
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.
[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()); int z = f(E()); — _end example_]
These alternatives are considered only if type deduction would otherwise fail.
If they yield more than one possible deducedA, the type deduction fails.
[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 correspondingtemplate-argumentcannot be deduced from a function call and thetemplate-argumentmust be explicitly specified.
— _end note_]
WhenPis a function type, function pointer type, or pointer-to-member-function type:
- If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.
- 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]) are satisfied.
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.
[Example 6: template <class T> int f(T (*p)(T));int g(int);int g(char);int i = f(g); — _end example_]
[Example 7: template <class T> int f(T, T (*p)(T));int g(int);char g(char);int i = f(1, g); — _end example_]
[Example 8: template <class T> int f(T, T (*p)(T));char g(char);template <class T> T g(T);int i = f(1, g); — _end example_]
[Example 9: template<bool B> struct X { static void f(short) requires B; static void f(short); };void test() { auto x = &X<true>::f; auto y = &X<false>::f; } — _end example_]