Шаблон функции определяет неограниченный набор связанных функций. [ Example: Семейство функций сортировки может быть объявлено следующим образом:
template<class T> class Array { }; template<class T> void sort(Array<T>&);
— end example ]
Шаблон функции может быть перегружен другими шаблонами функций и нешаблонными функциями ([dcl.fct]). Функция, не являющаяся шаблоном, не связана с шаблоном функции (т. Е. Никогда не считается специализацией), даже если она имеет то же имя и тип, что и потенциально сгенерированная специализация шаблона функции.139
То есть объявления функций, не являющихся шаблоном, не просто направляют разрешение перегрузки одноименных специализаций шаблонов функций. Если такая функция, не являющаяся шаблоном, присутствуетodr-used в программе, она должна быть определена; он не будет неявно создан с использованием определения шаблона функции.
Можно перегрузить шаблоны функций, чтобы две разные специализации шаблонов функций имели один и тот же тип. [ Example:
// translation unit 1: template<class T> void f(T*); void g(int* p) { f(p); // calls f<int>(int*) }
// translation unit 2: template<class T> void f(T); void h(int* p) { f(p); // calls f<int*>(int*) }
— end example ]
Подпись шаблона функции определена в разделе[intro.defs]. Имена параметров шаблона важны только для установления связи между параметрами шаблона и остальной частью подписи. [ Note: Два разных шаблона функций могут иметь идентичные типы возвращаемых функций и списки параметров функций, даже если одно разрешение перегрузки не может их различить.
template<class T> void f(); template<int I> void f(); // OK: overloads the first template // distinguishable with an explicit template argument list
— end note ]
Когда выражение, которое ссылается на параметр шаблона, используется в списке параметров функции или возвращаемом типе в объявлении шаблона функции, выражение, которое ссылается на параметр шаблона, является частью сигнатуры шаблона функции. Это необходимо для того, чтобы объявление шаблона функции в одной единице трансляции было связано с другим объявлением шаблона функции в другой единице трансляции и, наоборот, чтобы гарантировать, что шаблоны функций, которые должны быть различными, не связаны друг с другом. . [ Example:
template <int I, int J> A<I+J> f(A<I>, A<J>); // #1 template <int K, int L> A<K+L> f(A<K>, A<L>); // same as #1 template <int I, int J> A<I-J> f(A<I>, A<J>); // different from #1
— end example ] [ Note: Большинство выражений, использующих параметры шаблона, используют параметры шаблона, не являющиеся типами, но выражение может ссылаться на параметр типа. Например, вsizeof операторе можно использовать параметр типа шаблона . ] — end note
Два выражения, включающие параметры шаблона, рассматриваются, equivalent если два определения функции, содержащие эти выражения, удовлетворяют требованиямone-definition rule, за исключением того, что токены, используемые для наименования параметров шаблона, могут отличаться до тех пор, пока токен, используемый для наименования параметра шаблона в одном выражении, заменяется другим токеном, который называет тот же параметр шаблона в другом выражении. Для определения того,dependent names являются ли два эквивалентными, учитывается только само имя, а не результат поиска имени в контексте шаблона. Если несколько объявлений одного и того же шаблона функции отличаются в результате этого поиска имени, используется результат для первого объявления. [ Example:
template <int I, int J> void f(A<I+J>); // #1 template <int K, int L> void f(A<K+L>); // same as #1 template <class T> decltype(g(T())) h(); int g(int); template <class T> decltype(g(T())) h() // redeclaration of h() uses the earlier lookup { return g(T()); } // ...although the lookup here does find g(int) int i = h<int>(); // template argument substitution fails; g(int) // was not in scope at the first declaration of h()
— end example ] Два выражения, включающие параметры шаблона, которые не эквивалентны, - это functionally equivalent если для любого заданного набора аргументов шаблона результат вычисления выражения дает одно и то же значение.
Два шаблона функций - это equivalent если они объявлены в одной области действия, имеют одинаковое имя, одинаковые списки параметров шаблона и эквивалентные типы возвращаемых значений и списки параметров с использованием описанных выше правил для сравнения выражений, включающих параметры шаблона. Два шаблона функций functionally equivalent являются эквивалентными, за исключением того, что одно или несколько выражений, включающих параметры шаблона в возвращаемых типах и списках параметров, функционально эквивалентны с использованием описанных выше правил для сравнения выражений, включающих параметры шаблона. Если программа содержит объявления шаблонов функций, которые функционально эквивалентны, но не эквивалентны, это означает, что программа имеет неправильный формат, и диагностика не требуется.
[ Note: Это правило гарантирует, что эквивалентные объявления будут связаны друг с другом, при этом не требуя от реализации героических усилий, чтобы гарантировать, что функционально эквивалентные объявления будут рассматриваться как отдельные. Например, последние два объявления функционально эквивалентны и могут привести к неправильному формату программы:
// Guaranteed to be the same template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+10>); // Guaranteed to be different template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+11>); // Ill-formed, no diagnostic required template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+1+2+3+4>);
— end note ]
Если шаблон функции перегружен, использование специализации шаблона функции может быть неоднозначным, поскольку template argument deduction может связать специализацию шаблона функции с более чем одним объявлением шаблона функции. Partial ordering объявлений перегруженных шаблонов функций используется в следующих контекстах для выбора шаблона функции, на который ссылается специализация шаблона функции:
при разрешении перегрузки для вызова шаблона функции specialization ([over.match.best]);
когда берется адрес специализации шаблона функции;
когда оператор размещения delete, который является специализацией шаблона функции, выбран в соответствии с оператором размещения new ([basic.stc.dynamic.deallocation],[expr.new]);
когда afriend function declaration, an explicit instantiation или anexplicit specialization ссылаются на специализацию шаблона функции.
При частичном упорядочивании выбирается, какой из двух шаблонов функций более специализирован, чем другой, путем преобразования каждого шаблона по очереди (см. Следующий абзац) и выполнения вывода аргументов шаблона с использованием типа функции. Процесс дедукции определяет, является ли один из шаблонов более специализированным, чем другой. Если да, то в процессе частичного заказа выбирается более специализированный шаблон.
Чтобы создать преобразованный шаблон, для каждого типа, не-типа или параметра шаблона шаблона (включая template parameter packs их) синтезируйте уникальный тип, значение или шаблон класса соответственно и заменяйте его для каждого вхождения этого параметра в типе функции шаблона. [ Note: Тип, заменяющий заполнитель в типе значения, синтезированного для параметра шаблона, не являющегося типом, также является уникальным синтезированным типом. ] Если только один из шаблонов функций является нестатическим членом некоторого класса , считается, что в его список параметров функции вставлен новый первый параметр. Принимая во внимание , как CV-классификаторов (если таковые имеются), новый параметр имеет тип «ссылки на RValue » , если по желанию из вне или , если не имеет , и первый параметр другого шаблона имеет RValue ссылочный тип. В противном случае новый параметр имеет тип «ссылка lvalue на ». [ Это позволяет упорядочивать нестатический член по отношению к функции, не являющейся членом, а результаты должны быть эквивалентны упорядочению двух эквивалентных нечленов. ] [ — end note M AM cv McvAref-qualifierM && M ref-qualifiercvA Note: — end note Example:
struct A { }; template<class T> struct B { template<class R> int operator*(R&); // #1 }; template<class T, class R> int operator*(T&, R&); // #2 // The declaration of B::operator* is transformed into the equivalent of // template<class R> int operator*(B<A>&, R&); // #1a int main() { A a; B<A> b; b * a; // calls #1a }
— end example ]
Используя тип функции преобразованного шаблона функции, выполните определение типа для другого шаблона, как описано в[temp.deduct.partial].
[ Example:
template<class T> struct A { A(); }; template<class T> void f(T); template<class T> void f(T*); template<class T> void f(const T*); template<class T> void g(T); template<class T> void g(T&); template<class T> void h(const T&); template<class T> void h(A<T>&); void m() { const int* p; f(p); // f(const T*) is more specialized than f(T) or f(T*) float x; g(x); // ambiguous: g(T) or g(T&) A<int> z; h(z); // overload resolution selects h(A<T>&) const A<int> z2; h(z2); // h(const T&) is called because h(A<T>&) is not callable }
— end example ]
[ Note: Поскольку частичное упорядочение в контексте вызова учитывает только параметры, для которых есть явные аргументы вызова, некоторые параметры игнорируются (а именно, пакеты параметров функций, параметры с аргументами по умолчанию и параметры с многоточием). [ Example:
template<class T> void f(T); // #1 template<class T> void f(T*, int=1); // #2 template<class T> void g(T); // #3 template<class T> void g(T*, ...); // #4
int main() { int* ip; f(ip); // calls #2 g(ip); // calls #4 }
— end example ] [ Example:
template<class T, class U> struct A { }; template<class T, class U> void f(U, A<U, T>* p = 0); // #1 template< class U> void f(U, A<U, U>* p = 0); // #2 template<class T > void g(T, T = T()); // #3 template<class T, class... U> void g(T, U ...); // #4 void h() { f<int>(42, (A<int, int>*)0); // calls #2 f<int>(42); // error: ambiguous g(42); // error: ambiguous }
— end example ] [ Example:
template<class T, class... U> void f(T, U...); // #1 template<class T > void f(T); // #2 template<class T, class... U> void g(T*, U...); // #3 template<class T > void g(T); // #4 void h(int i) { f(&i); // error: ambiguous g(&i); // OK: calls #3 }
— end example ] ] — end note