Шаблон функции может быть перегружен либо (не шаблонными) функциями его имени, либо (другими) шаблонами функций с тем же именем. Когда вызов этого имени записан (явно или неявно с использованием обозначения оператора), template argument deduction и проверка любого явного template arguments значения выполняется для каждого шаблона функции, чтобы найти значения аргументов шаблона (если есть), которые можно использовать с этим шаблоном функции для создания экземпляра специализация шаблона функции, которая может быть вызвана с аргументами вызова. Для каждого шаблона функции, если вывод аргументов и проверка завершаются успешно, template-arguments (выведенные и / или явные) используются для синтеза объявления специализации шаблона одной функции, которая добавляется к набору функций-кандидатов, которые будут использоваться при разрешении перегрузки. Если для данного шаблона функции выведение аргументов не удается или специализация шаблона синтезированной функции была бы неправильно сформирована, такая функция не добавляется к набору функций-кандидатов для этого шаблона. Полный набор функций-кандидатов включает все синтезированные объявления и все одноименные перегруженные функции, не являющиеся шаблонными. Синтезированные объявления обрабатываются как любые другие функции в оставшейся части разрешения перегрузки, за исключением случаев, явно указанных в [over.match.best].143
[ Example:
template<class T> T max(T a, T b) { return a>b?a:b; } void f(int a, int b, char c, char d) { int m1 = max(a,b); // max(int a, int b) char m2 = max(c,d); // max(char a, char b) int m3 = max(a,c); // error: cannot generate max(int,char) }
Добавление нешаблонной функции
int max(int,int);
в приведенном выше примере разрешит третий вызов, предоставив функцию, которая может быть вызвана max(a,c) после использования стандартного преобразования char в int for c. ] — end example
[ Example: Вот пример преобразования аргумента функции, участвующего в template-argument дедукции:
template<class T> struct B { /* ... */ }; template<class T> struct D : public B<T> { /* ... */ }; template<class T> void f(B<T>&); void g(B<int>& bi, D<int>& di) { f(bi); // f(bi) f(di); // f((B<int>&)di) }
— end example ]
[ Example: Вот пример преобразования аргумента функции, не участвующего в template-parameter дедукции:
template<class T> void f(T*,int); // #1 template<class T> void f(T,char); // #2 void h(int* pi, int i, char c) { f(pi,i); // #1: f<int>(pi,i) f(pi,c); // #2: f<int*>(pi,c) f(i,c); // #2: f<int>(i,c); f(i,i); // #2: f<int>(i,char(i)) }
— end example ]
Для ввода специализации в набор функций-кандидатов требуется только подпись специализации шаблона функции. Следовательно, для разрешения вызова, для которого возможна специализация шаблона, требуется только объявление шаблона функции. [ Example:
template<class T> void f(T); // declaration void g() { f("Annemarie"); // call of f<const char*> }
Вызов f правильно сформирован, даже если шаблон f только объявлен и не определен в точке вызова. Программа будет плохо сформирована, еслиf<const char*>в некоторой единице трансляции не будет присутствовать явно или неявно сгенерированная специализация for . ] — end example
Параметры специализаций шаблонов функций не содержат типов параметров шаблона. Набор преобразований, разрешенных для выведенных аргументов, ограничен, потому что процесс вывода аргументов создает шаблоны функций с параметрами, которые либо точно соответствуют аргументам вызова, либо отличаются только способами, которые могут быть объединены разрешенными ограниченными преобразованиями. Невыведенные аргументы допускают полный диапазон преобразований. Также обратите внимание, что это [over.match.best] указывает, что функции, не являющейся шаблоном, будет отдано предпочтение по сравнению со специализацией шаблона, если в остальном эти две функции являются одинаково хорошими кандидатами на совпадение по перегрузке.