Если шаблон функции перегружен, использование специализации шаблона функции может быть неоднозначным, поскольку template argument deduction может связать специализацию шаблона функции с более чем одним объявлением шаблона функции. Partial ordering объявлений перегруженных шаблонов функций используется в следующих контекстах для выбора шаблона функции, на который ссылается специализация шаблона функции:
при разрешении перегрузки для вызова шаблона функции specialization ([over.match.best]);
когда берется адрес специализации шаблона функции;
когда оператор размещения delete, который является специализацией шаблона функции, выбран в соответствии с оператором размещения new ([basic.stc.dynamic.deallocation], [expr.new]);
когда a friend function declaration, an explicit instantiation или an explicit specialization ссылаются на специализацию шаблона функции.
При частичном упорядочивании выбирается, какой из двух шаблонов функций более специализирован, чем другой, путем преобразования каждого шаблона по очереди (см. Следующий абзац) и выполнения вывода аргументов шаблона с использованием типа функции. Процесс дедукции определяет, является ли один из шаблонов более специализированным, чем другой. Если да, то в процессе частичного заказа выбирается более специализированный шаблон.
Чтобы создать преобразованный шаблон, для каждого типа, не-типа или параметра шаблона шаблона (включая template parameter packs их) синтезируйте уникальный тип, значение или шаблон класса соответственно и заменяйте его для каждого вхождения этого параметра в типе функции шаблона. [ Note: Тип, заменяющий заполнитель в типе значения, синтезированного для параметра шаблона, не являющегося типом, также является уникальным синтезированным типом. ] Если только один из шаблонов функций является нестатическим членом некоторого класса , считается, что в его список параметров функции вставлен новый первый параметр. Принимая во внимание , как CV-классификаторов (если таковые имеются), новый параметр имеет тип «ссылки на RValue » , если по желанию из вне или , если не имеет , и первый параметр другого шаблона имеет RValue ссылочный тип. В противном случае новый параметр имеет тип «ссылка lvalue на ». [ Это позволяет упорядочивать нестатический член по отношению к функции, не являющейся членом, а результаты должны быть эквивалентны упорядочению двух эквивалентных нечленов. ] [ — end note M A M cv Mcv Aref-qualifierM && M ref-qualifier cv A 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