17 Templates [temp]

17.7 Template instantiation and specialization [temp.spec]

17.7.3 Explicit specialization [temp.expl.spec]

Явная специализация любого из следующего:

  • шаблон функции

  • шаблон класса

  • шаблон переменных

  • функция-член шаблона класса

  • статический член данных шаблона класса

  • класс-член шаблона класса

  • перечисление членов шаблона класса

  • шаблон класса члена класса или шаблона класса

  • шаблон функции-члена класса или шаблона класса

может быть объявлено посредством объявления, представленного template<>; то есть:

explicit-specialization:
	template < > declaration

[Example:

template<class T> class stream;

template<> class stream<char> { /* ... */ };

template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }

template<> void sort<char*>(Array<char*>&);

Учитывая эти объявления, stream<char> будет использоваться как определение потоков chars; другие потоки будут обрабатываться специализациями шаблонов классов, созданными из шаблона класса. Точно так же sort<char*> будет использоваться функция сортировки для аргументов типа Array<char*>; другие Array типы будут отсортированы по функциям, сгенерированным из шаблона. ]end example

Явная специализация может быть объявлена в любой области , в которой может быть определен соответствующий первичный шаблон ([namespace.memdef],[class.mem],[temp.mem]).

Объявление явной специализации шаблона функции, шаблона класса или шаблона переменной должно предшествовать объявлению явной специализации. [ Note: Требуется декларация, но не определение шаблона. ] Определение класса или шаблона класса должно предшествовать объявлению явной специализации для шаблона члена этого класса или шаблона класса. [end noteExample:

template<> class X<int> { /* ... */ };          // error: X not a template

template<class T> class X;

template<> class X<char*> { /* ... */ };        // OK: X is a template

end example]

Функция-член, шаблон функции-члена, класс-член, перечисление члена, шаблон класса-члена, статический член-данные или статический элемент-данные-шаблон шаблона класса могут быть явно специализированы для неявно создаваемой специализации класса; в этом случае определение шаблона класса должно предшествовать явной специализации для члена шаблона класса. Если такая явная специализация для члена шаблона класса называет неявно объявленную специальную функцию-член (предложение[special]), программа плохо сформирована.

Член явно специализированного класса не создается неявно из объявления члена шаблона класса; вместо этого член специализации шаблона класса должен быть явно определен, если требуется его определение. В этом случае определение явной специализации шаблона класса должно входить в область видимости в точке, в которой определяется член. Определение явно специализированного класса не связано с определением сгенерированной специализации. То есть его члены не обязательно должны иметь те же имена, типы и т. Д., Что и члены сгенерированной специализации. Члены явно специализированного шаблона класса определяются так же, как члены обычных классов, и не используютtemplate<> синтаксис. То же самое верно и при определении члена явно специализированного класса-члена. Однакоtemplate<> он используется при определении члена явно специализированного шаблона класса члена, который специализирован как шаблон класса. [Example:

template<class T> struct A {
  struct B { };
  template<class U> struct C { };
};

template<> struct A<int> {
  void f(int);
};

void h() {
  A<int> a;
  a.f(16);          // A<int>​::​f must be defined somewhere
}

// template<> not used for a member of an explicitly specialized class template
void A<int>::f(int) { /* ... */ }

template<> struct A<char>::B {
  void f();
};
// template<> also not used when defining a member of an explicitly specialized member class
void A<char>::B::f() { /* ... */ }

template<> template<class U> struct A<char>::C {
  void f();
};
// template<> is used when defining a member of an explicitly specialized member class template
// specialized as a class template
template<>
template<class U> void A<char>::C<U>::f() { /* ... */ }

template<> struct A<short>::B {
  void f();
};
template<> void A<short>::B::f() { /* ... */ }              // error: template<> not permitted

template<> template<class U> struct A<short>::C {
  void f();
};
template<class U> void A<short>::C<U>::f() { /* ... */ }    // error: template<> required

end example]

Если шаблон, шаблон члена или член шаблона класса явно специализирован, тогда эта специализация должна быть объявлена ​​перед первым использованием этой специализации, которая вызовет неявное создание экземпляра, в каждой единице перевода, в которой происходит такое использование. ; Диагностика не требуется. Если программа не предоставляет определение для явной специализации и либо специализация используется таким образом, что может иметь место неявное создание экземпляра, либо член является виртуальной функцией-членом, программа имеет неправильный формат, диагностика не требуется. Неявное создание экземпляра никогда не создается для явной специализации, которая объявлена, но не определена. [Example:

class String { };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }

void f(Array<String>& v) {
  sort(v);          // use primary template sort(Array<T>&), T is String
}

template<> void sort<String>(Array<String>& v);     // error: specialization after use of primary template
template<> void sort<>(Array<char*>& v);            // OK: sort<char*> not yet used
template<class T> struct A {
  enum E : T;
  enum class S : T;
};
template<> enum A<int>::E : int { eint };           // OK
template<> enum class A<int>::S : int { sint };     // OK
template<class T> enum A<T>::E : T { eT };
template<class T> enum class A<T>::S : T { sT };
template<> enum A<char>::E : char { echar };        // ill-formed, A<char>​::​E was instantiated
                                                    // when A<char> was instantiated
template<> enum class A<char>::S : char { schar };  // OK

end example]

Размещение явных объявлений специализации для шаблонов функций, шаблонов классов, шаблонов переменных, функций-членов шаблонов классов, статических элементов данных шаблонов классов, классов-членов шаблонов классов, перечислений элементов шаблонов классов, шаблонов классов-членов шаблонов классов, функций-членов шаблоны шаблонов классов, шаблоны элементов статических данных шаблонов классов, функции-члены шаблонов-членов шаблонов классов, функции-члены шаблонов-членов нешаблонных классов, шаблоны элементов статических данных нешаблонных классов, шаблоны функций-членов классов-членов шаблоны классов и т. д., а также размещение объявлений частичной специализации шаблонов классов, шаблонов переменных, шаблонов классов-членов нешаблонных классов, статических шаблонов элементов данных нешаблонных классов, шаблонов классов-членов шаблонов классов и т. д. влияет на то, правильно ли сформирована программа в соответствии с относительным расположением явной спецификации lization и их точки создания в блоке перевода, как указано выше и ниже. При написании специализации внимательно относитесь к ее расположению; или заставить его скомпилировать будет такое испытание, чтобы разжечь его самосожжение.

Явная специализация шаблона находится в области пространства имен, в котором был определен шаблон. [Example:

namespace N {
  template<class T> class X { /* ... */ };
  template<class T> class Y { /* ... */ };

  template<> class X<int> { /* ... */ };        // OK: specialization in same namespace
  template<> class Y<double>;                   // forward-declare intent to specialize for double
}

template<> class N::Y<double> { /* ... */ };    // OK: specialization in enclosing namespace
template<> class N::Y<short> { /* ... */ };     // OK: specialization in enclosing namespace

end example]

Объект, simple-template-id который называет явную специализацию шаблона класса, которая была объявлена, но не определена, может использоваться точно так же, как имена других не полностью определенных классов ([basic.types]). [Example:

template<class T> class X;                      // X is a class template
template<> class X<int>;

X<int>* p;                                      // OK: pointer to declared class X<int>
X<int> x;                                       // error: object of incomplete class X<int>

end example]

Конечный конец template-argument можно не указывать в template-id явном названии специализации шаблона функции, при условии, что он может быть выведен из типа аргумента функции. [Example:

template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v);

// explicit specialization for sort(Array<int>&)
// with deduced template-argument of type int
template<> void sort(Array<int>&);

end example]

Функция с тем же именем, что и шаблон, и типом, который точно соответствует специализации шаблона, не является явной специализацией ([temp.fct]).

Явная специализация шаблона функции или переменной является встроенной, только если она объявлена ​​соinline спецификатором или определена как удаленная, и независимо от того, является ли ее шаблон функции или переменной встроенным. [Example:

template<class T> void f(T) { /* ... */ }
template<class T> inline T g(T) { /* ... */ }

template<> inline void f<>(int) { /* ... */ }   // OK: inline
template<> int g<>(int) { /* ... */ }           // OK: not inline

end example]

Явная специализация статического элемента данных шаблона или явная специализация шаблона статического элемента данных является определением, если объявление включает инициализатор; в противном случае это декларация. [ Note: Определение статического элемента данных шаблона, который требует инициализации по умолчанию, должно использовать braced-init-list:

template<> X Q<int>::x;                         // declaration
template<> X Q<int>::x ();                      // error: declares a function
template<> X Q<int>::x { };                     // definition

end note]

Член или шаблон члена шаблона класса может быть явно специализирован для данного неявного создания экземпляра шаблона класса, даже если член или шаблон члена определен в определении шаблона класса. Явная специализация элемента или шаблона элемента указывается с использованием синтаксиса явной специализации. [Example:

template<class T> struct A {
  void f(T);
  template<class X1> void g1(T, X1);
  template<class X2> void g2(T, X2);
  void h(T) { }
};

// specialization
template<> void A<int>::f(int);

// out of class member template definition
template<class T> template<class X1> void A<T>::g1(T, X1) { }

// member template specialization
template<> template<class X1> void A<int>::g1(int, X1);

// member template specialization
template<> template<>
  void A<int>::g1(int, char);           // X1 deduced as char
template<> template<>
  void A<int>::g2<char>(int, char);     // X2 specified as char

// member specialization even if defined in class definition
template<> void A<int>::h(int) { }

end example]

Член или шаблон члена могут быть вложены во многие шаблоны включающих классов. При явной специализации для такого члена объявлению члена должен предшествовать a template<> для каждого шаблона включающего класса, который явно специализирован. [Example:

template<class T1> class A {
  template<class T2> class B {
    void mf();
  };
};
template<> template<> class A<int>::B<double>;
template<> template<> void A<char>::B<char>::mf();

end example]

В явном объявлении специализации для члена шаблона класса или шаблона члена, который появляется в области пространства имен, шаблон члена и некоторые из включающих его шаблонов классов могут оставаться неспециализированными, за исключением того, что объявление не должно явно специализировать шаблон члена класса, если его шаблоны включающих классов также не являются явно специализированными. В таком явном объявлении специализации должно быть предоставлено ключевое слово, template за которым следует a template-parameter-list, вместо template<> предшествующего явного объявления специализации члена. Типы template-parameters в template-parameter-list должны быть такими же, как те, которые указаны в определении первичного шаблона. [Example:

template <class T1> class A {
  template<class T2> class B {
    template<class T3> void mf1(T3);
    void mf2();
  };
};
template <> template <class X>
  class A<int>::B {
      template <class T> void mf1(T);
  };
template <> template <> template<class T>
  void A<int>::B<double>::mf1(T t) { }
template <class Y> template <>
  void A<Y>::B<double>::mf2() { }       // ill-formed; B<double> is specialized but
                                        // its enclosing class template A is not

end example]

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

Явное объявление специализации не должно быть дружественным объявлением.

Аргументы функции по умолчанию не должны указываться в объявлении или определении для одной из следующих явных специализаций:

  • явная специализация шаблона функции;

  • явная специализация шаблона функции-члена;

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