17 Templates [temp]

17.8 Function template specializations [temp.fct.spec]

17.8.2 Template argument deduction [temp.deduct]

17.8.2.4 Deducing template arguments during partial ordering [temp.deduct.partial]

Вывод аргументов шаблона выполняется путем сравнения определенных типов, связанных с двумя сравниваемыми шаблонами функций.

Для определения частичного упорядочивания используются два набора типов. Для каждого из задействованных шаблонов существует исходный тип функции и тип преобразованной функции. [ Note: Создание преобразованного типа описано в [temp.func.order]. ] В процессе вывода преобразованный тип используется в качестве шаблона аргумента, а исходный тип другого шаблона - в качестве шаблона параметра. Этот процесс выполняется дважды для каждого типа, участвующего в сравнении частичного упорядочения: один раз с использованием преобразованного шаблона-1 в качестве шаблона аргумента и шаблона-2 в качестве шаблона параметра и снова с использованием преобразованного шаблона-2 в качестве шаблона аргумента и шаблона-1. в качестве шаблона параметра.end note

Типы, используемые для определения порядка, зависят от контекста, в котором выполняется частичное упорядочение:

  • В контексте вызова функции используются те типы параметров функции, для которых у вызова функции есть аргументы.141

  • В контексте вызова функции преобразования используются типы возвращаемых значений шаблонов функций преобразования.

  • В other contexts шаблоне функции используется тип функции.

Каждый тип, указанный выше из шаблона параметра, и соответствующий тип из шаблона аргумента используются как типы P и A. Если конкретный элемент P не содержит тех, template-parameters которые участвуют в выводе аргументов шаблона, это P не используется для определения порядка.

Перед тем, как будет выполнено частичное упорядочение, определенные преобразования выполняются в типах, используемых для частичного упорядочивания:

  • Если P является ссылочным типом, P заменяется указанным типом.

  • Если A является ссылочным типом, A заменяется указанным типом.

Если оба P и A были ссылочными типами (перед заменой на тип, упомянутый выше), определите, какой из двух типов (если есть) более квалифицирован cv, чем другой; в противном случае типы считаются равноценными cv для целей частичного упорядочивания. Результат этого определения будет использован ниже.

Удалите все квалификаторы cv верхнего уровня:

  • Если P это тип с квалификацией cv, P он заменяется версией с неквалифицированной версией P.

  • Если A это тип с квалификацией cv, A он заменяется версией с неквалифицированной версией A.

Используя полученные типы P и A, затем выполняется вывод, как описано в [temp.deduct.type]. Если P это параметр функции пакета, тип A каждого оставшегося типа параметра шаблона аргумента сравнивается с типом P из declarator-idпараметра функции пакета. Каждое сравнение выводит аргументы шаблона для последующих позиций в пакетах параметров шаблона, расширенных пакетом параметров функции. Точно так же, если он A был преобразован из пакета параметров функции, он сравнивается с каждым оставшимся типом параметра шаблона параметра. Если вывод для данного типа успешен, тип из шаблона аргумента считается как минимум таким же специализированным, как тип из шаблона параметра. [Example:

template<class... Args>           void f(Args... args);         // #1
template<class T1, class... Args> void f(T1 a1, Args... args);  // #2
template<class T1, class T2>      void f(T1 a1, T2 a2);         // #3

f();                // calls #1
f(1, 2, 3);         // calls #2
f(1, 2);            // calls #3; non-variadic template #3 is more specialized
                    // than the variadic templates #1 and #2

end example]

Если для данного типа, удержание преуспевает в обоих направлениях (т.е. типы идентичны после вышеуказанных преобразований) , и оба , P и A были ссылочные типы (прежде , чем быть заменен с типом упомянутого выше):

  • если тип из шаблона аргумента был ссылкой lvalue, а тип из шаблона параметра - нет, тип параметра не считается по крайней мере таким же специализированным, как тип аргумента; иначе,

  • если тип из шаблона аргумента более квалифицирован cv, чем тип из шаблона параметра (как описано выше), тип параметра не считается по крайней мере таким же специализированным, как тип аргумента.

Шаблон функции F является шаблоном at least as specialized asфункции, G если для каждой пары типов, используемых для определения порядка, тип from F является по крайней мере таким же специализированным, как тип from G. F является more specialized than G ли F это , по крайней мере специализированы , как G и G не по крайней мере специализированы , как F.

Если после рассмотрения выше, шаблон функции F является , по крайней мере специализировано в качестве шаблона функции , G и наоборот, и если G есть пакет параметров трейлинга , для которого F не имеет соответствующий параметр, а если F не имеет параметр трейлинга пакета, то F есть более специализированный, чем G.

В большинстве случаев для успешного вывода все параметры шаблона должны иметь значения, но для целей частичного упорядочивания параметр шаблона может оставаться без значения при условии, что он не используется в типах, используемых для частичного упорядочивания. [ Note: Параметр шаблона, используемый в невыведенном контексте, считается использованным. ] [end noteExample:

template <class T> T f(int);            // #1
template <class T, class U> T f(U);     // #2
void g() {
  f<int>(1);                            // calls #1
}

end example]

[ Note: Частичное упорядочение шаблонов функций, содержащих пакеты параметров шаблона, не зависит от количества выведенных аргументов для этих пакетов параметров шаблона. ] [end noteExample:

template<class ...> struct Tuple { };
template<class ... Types> void g(Tuple<Types ...>);                 // #1
template<class T1, class ... Types> void g(Tuple<T1, Types ...>);   // #2
template<class T1, class ... Types> void g(Tuple<T1, Types& ...>);  // #3

g(Tuple<>());                   // calls #1
g(Tuple<int, float>());         // calls #2
g(Tuple<int, float&>());        // calls #3
g(Tuple<int>());                // calls #3

end example]

Аргументы по умолчанию не считаются аргументами в этом контексте; они становятся аргументами только после выбора функции.