Можно перегрузить шаблоны функций, чтобы две разные специализации шаблонов функций имели один и тот же тип. [ 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 ]