17 Templates [temp]

17.8 Function template specializations [temp.fct.spec]

17.8.1 Explicit template argument specification [temp.arg.explicit]

Аргументы шаблона могут быть указаны при ссылке на специализацию шаблона функции путем уточнения имени шаблона функции списком template-arguments таким же образом, как template-arguments это указывается при использовании специализации шаблона класса. [Example:

template<class T> void sort(Array<T>& v);
void f(Array<dcomplex>& cv, Array<int>& ci) {
  sort<dcomplex>(cv);                   // sort(Array<dcomplex>&)
  sort<int>(ci);                        // sort(Array<int>&)
}

а также

template<class U, class V> U convert(V v);

void g(double d) {
  int i = convert<int,double>(d);       // int convert(double)
  char c = convert<char,double>(d);     // char convert(double)
}

end example]

Список аргументов шаблона может быть указан при ссылке на специализацию шаблона функции.

  • когда функция вызывается,

  • когда берется адрес функции, когда функция инициализирует ссылку на функцию или когда формируется указатель на функцию-член,

  • в явной специализации,

  • в явном экземпляре, или

  • в объявлении друга.

Конечные аргументы шаблона, которые могут быть deduced или получены по умолчанию, template-arguments могут быть исключены из списка явных template-arguments. Завершающий, template parameter pack не выведенный иным образом, будет выведен в пустую последовательность аргументов шаблона. Если все аргументы шаблона могут быть выведены, все они могут быть опущены; в этом случае сам пустой список аргументов шаблона <> также может быть опущен. В контекстах, где дедукция выполняется и терпит неудачу, или в контекстах, где дедукция не выполняется, если указан список аргументов шаблона и он, вместе с любыми аргументами шаблона по умолчанию, идентифицирует одну специализацию шаблона функции, тогда template-id это lvalue для функции специализация шаблона. [Example:

template<class X, class Y> X f(Y);
template<class X, class Y, class ... Z> X g(Y);
void h() {
  int i = f<int>(5.6);          // Y is deduced to be double
  int j = f(5.6);               // ill-formed: X cannot be deduced
  f<void>(f<int, bool>);        // Y for outer f deduced to be int (*)(bool)
  f<void>(f<int>);              // ill-formed: f<int> does not denote a single function template specialization
  int k = g<int>(5.6);          // Y is deduced to be double, Z is deduced to an empty sequence
  f<void>(g<int, bool>);        // Y for outer f is deduced to be int (*)(bool),
                                // Z is deduced to an empty sequence
}

end example]

[ Note: Пустой список аргументов шаблона может использоваться, чтобы указать, что данное использование относится к специализации шаблона функции, даже если[dcl.fct]видна не являющаяся шаблоном функция ( ), которая в противном случае использовалась бы. Например:

template <class T> int f(T);    // #1
int f(int);                     // #2
int k = f(1);                   // uses #2
int l = f<>(1);                 // uses #1

end note]

Присутствующие аргументы шаблона должны быть указаны в порядке объявления их соответствующих template-parameters. Список аргументов шаблона не должен указывать больше, template-arguments чем есть соответствующие, template-parameters если один из них не template-parameters является пакетом параметров шаблона. [Example:

template<class X, class Y, class Z> X f(Y,Z);
template<class ... Args> void f2();
void g() {
  f<int,const char*,double>("aa",3.0);
  f<int,const char*>("aa",3.0); // Z is deduced to be double
  f<int>("aa",3.0);             // Y is deduced to be const char*, and Z is deduced to be double
  f("aa",3.0);                  // error: X cannot be deduced
  f2<char, short, int, long>(); // OK
}

end example]

Неявные преобразования (Clause [conv]) будут выполнены для аргумента функции, чтобы преобразовать его в тип соответствующего параметра функции, если тип параметра не содержит никаких, template-parameters которые участвуют в выводе аргумента шаблона. [ Note: Параметры шаблона не участвуют в выводе аргументов шаблона, если они явно указаны. Например,

template<class T> void f(T);

class Complex {
  Complex(double);
};

void g() {
  f<Complex>(1);    // OK, means f<Complex>(Complex(1))
}

end note]

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

[ Note: Для простых имен функций argument dependent lookup применяется, даже если имя функции не отображается в рамках вызова. Это потому, что вызов по-прежнему имеет синтаксическую форму вызова функции ([basic.lookup.unqual]). Но когда используется шаблон функции с явными аргументами шаблона, вызов не имеет правильной синтаксической формы, если не существует шаблона функции с таким именем, видимого в точке вызова. Если такое имя не отображается, вызов не имеет синтаксической правильной формы и поиск, зависящий от аргументов, не применяется. Если такое имя видно, применяется поиск, зависящий от аргументов, и дополнительные шаблоны функций могут быть найдены в других пространствах имен. [Example:

namespace A {
  struct B { };
  template<int X> void f(B);
}
namespace C {
  template<class T> void f(T t);
}
void g(A::B b) {
  f<3>(b);          // ill-formed: not a function call
  A::f<3>(b);       // well-formed
  C::f<3>(b);       // ill-formed; argument dependent lookup applies only to unqualified names
  using C::f;
  f<3>(b);          // well-formed because C​::​f is visible; then A​::​f is found by argument dependent lookup
}

end example] ]end note

Вывод аргументов шаблона может расширить последовательность аргументов шаблона, соответствующую пакету параметров шаблона, даже если последовательность содержит явно указанные аргументы шаблона. [Example:

template<class ... Types> void f(Types ... values);

void g() {
  f<int*, float*>(0, 0, 0);     // Types is deduced to the sequence int*, float*, int
}

end example]