Вывод аргументов шаблона выполняется путем сравнения каждого типа параметра шаблона функции (вызовите его P), который содержит, template-parameters который участвует в выводе аргумента шаблона, с типом соответствующего аргумента вызова (вызовите его A), как описано ниже. Если удаление ссылок и cv-квалификаторов из P дает std::initializer_list<P'> или P'[N] для некоторых P' и, N а аргумент является непустым списком инициализатора ([dcl.init.list]), то вместо этого выполняется вывод для каждого элемента списка инициализаторов, принимая P' в качестве типа параметра шаблона функции и элемент инициализатора в качестве аргумента, а в P'[N] случае, если N это не типовой параметр шаблона, N выводится из длины списка инициализаторов. В противном случае аргумент списка инициализаторов заставляет параметр считаться невыведенным context ([temp.deduct.type]). [ Example:
template<class T> void f(std::initializer_list<T>); f({1,2,3}); // T deduced to int f({1,"asdf"}); // error: T deduced to both int and const char* template<class T> void g(T); g({1,2,3}); // error: no argument deduced for T template<class T, int N> void h(T const(&)[N]); h({1,2,3}); // T deduced to int, N deduced to 3 template<class T> void j(T const(&)[3]); j({42}); // T deduced to int, array bound not considered struct 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 to 3 template<int M, int N> void m(int const(&)[M][N]); m({{1,2},{3,4}}); // M and N both deduced to 2 template<class T, int N> void n(T const(&)[N], T); n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
— end example ] Для параметра пакета функции , которое происходит в конце parameter-declaration-list, удержание выполняется для каждого оставшегося аргумента вызова, принимая тип P из declarator-idпараметра функции пакета в качестве соответствующего шаблона функции типа параметра. Каждый вывод выводит аргументы шаблона для последующих позиций в пакетах параметров шаблона, расширенных пакетом параметров функции. Когда пакет параметров функции появляется в невыведенном контексте ([temp.deduct.type]), тип этого пакета параметров никогда не выводится. [ Example:
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 is deduced to int, float, const int g(x, y, z); // T1 is deduced to int; Types is deduced to float, int g1(x, y, z); // error: Types is not deduced g1<int, int, int>(x, y, z); // OK, no deduction occurs }
— end example ]
Если P это не ссылочный тип:
Если A это тип массива, то тип указателя, созданный объектом, array-to-pointer standard conversion используется вместо A вывода типа; иначе,
Если A это тип функции, тип указателя, созданный с помощью function-to-pointer standard conversion , используется вместо A вывода типа; иначе,
Если A это тип с квалификацией cv, квалификаторы cv верхнего уровня Aдля типа игнорируются при выводе типа.
Если P это тип с квалификацией cv, квалификаторы cv верхнего уровня Pдля типа игнорируются при выводе типа. Если P это ссылочный тип, тип, на который ссылается, P используется для вывода типа. [ Example:
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 - это ссылка rvalue на параметр шаблона cv-unqualified, который не представляет параметр шаблона шаблона класса (во время вывода аргументов шаблона класса ([over.match.class.deduct])). Если P это ссылка пересылки, а аргумент - lvalue, тип «lvalue ссылка на A» используется вместо A для вывода типа. [ Example:
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 lvalue template <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 ]
В общем, процесс вывода пытается найти значения аргументов шаблона, которые сделают вывод A идентичным A (послеA преобразования типа, как описано выше). Однако есть три случая, в которых допускается различие:
Если исходный P является ссылочным типом, выведенный A (т. Е. Тип, на который ссылается ссылка) может быть более квалифицированным cv, чем преобразованный A.
Преобразованный A может быть другим указателем или указателем на тип члена, который может быть преобразован в выведенный с A помощью function pointer conversion и / или qualification conversion.
Если P есть класс и P имеет форму simple-template-id, то преобразованный A может быть производным классом выведенного A. Аналогично, если P это указатель на класс формы simple-template-id, преобразованный A может быть указателем на производный класс, на который указывает выведенный A.
Эти альтернативы рассматриваются только в том случае, если в противном случае определение типа не удалось бы. Если они дают более одного возможного Aвывода, вывод типа не выполняется. [ Note: Если a template-parameter не используется ни в одном из параметров функции шаблона функции или используется только в невыведенном контексте, его соответствие template-argument не может быть выведено из вызова функции и template-argument должно быть явно указано. ] — end note
Когда P это тип функции, тип указателя функции или указатель на тип функции-члена:
Если аргумент является набором перегрузки, содержащим один или несколько шаблонов функций, параметр обрабатывается как невыведенный контекст.
Если аргумент является набором перегрузки (не содержащим шаблонов функций), пробный вывод аргумента предпринимается с использованием каждого из членов набора. Если вывод успешен только для одного из элементов набора перегрузки, этот член используется в качестве значения аргумента для вывода. Если вывод успешен для более чем одного члена набора перегрузки, параметр обрабатывается как невыведенный контекст.
[ Example:
// 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 ]
[ Example:
// 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 ]
[ Example:
// 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 ]
Если вывод успешен для всех параметров, которые содержат, template-parameters которые участвуют в выводе аргументов шаблона, и все аргументы шаблона явно указаны, выведены или получены из аргументов шаблона по умолчанию, оставшиеся параметры затем сравниваются с соответствующими аргументами. Для каждого оставшегося параметра P с типом, который не был зависимым до подстановки любых явно заданных аргументов шаблона, если соответствующий аргумент A не может быть неявно преобразован в P, выведение не выполняется. [ Note: Параметры с зависимыми типами, которые не template-parameters участвуют в выводе аргументов шаблона, и параметры, которые стали независимыми из-за подстановки явно указанных аргументов шаблона, будут проверяться во время разрешения перегрузки. ] [ — end note Example:
template <class T> struct Z { typedef typename T::x xx; }; template <class T> typename Z<T>::xx f(void *, T); // #1 template <class T> void f(int, T); // #2 struct A {} a; int main() { f(1, a); // OK, deduction fails for #1 because there is no conversion from int to void* }
— end example ]