.. include:: Templates and Specializations ============================= Partial Template Specialization Examples ---------------------------------------- This modified example, taken from `partial template specialization `_, shows how a primary class template can be partially specialized for a given category of template arguments: .. code-block:: cpp // Primary template template class A { public: void describe() const { cout << "Primary class template." << endl; } }; // #1: Partial specialization in which the 2nd parameter is a pointer to the type of the first generic parameter. template class A { public: void describe() const { cout << "uses partial template specialization #1 'class A', in which the 2nd parameter is a pointer to 'type of the first parameter'." << endl; } }; class X { //.... omitted }; A a; // Instantiates partial template specialization above. a.describe(); // prints: "uses partial template specialization #1 'class A', in which the 2nd parameter is a pointer to 'type of the first parameter'." // #2: Partial specialization in which the first parameter is always a pointer. template class A { public: void describe() const { cout << "uses partial template specialization #2 'class A', in which the first parameter is a pointer." << endl; } }; A a; // Instantiates partial template specialization above. a.describe(); // prints: "uses partial template specialization #2 'class A', in which the first parameter is a pointer." // #3: Partial specialization in which first parameter is always int, the 2nd parameter is always a pointer // and the third is the scalar 5 template class A { public: void describe() const { cout << "uses partial template specialization #3 'class A', in which the first parameter is an int, and the 2nd is a pointer and the third is the scalar 5." << endl; } }; A<6, X *, 5> a; // Instantiates partial template specialization above. a.describe(); // prints: "uses partial template specialization #3 'class A', in which the first parameter is an int, and the 2nd is a pointer and the third is the scalar 5." // #4: Partial specialization in which the second parameter is always a pointer. template class A { public: void describe() const { cout << "uses partial template specialization #4 'class A', in which The second parameter is a pointer." << endl; } }; class Y {//... }; A a; a.describe(); // prints: "uses partial template specialization #4 'class A', in which The second parameter is a pointer." The output from these partial template instantiations further illustrate when a partial template specializations occurs: .. code-block:: cpp // given the template A as defined above and its partial specializations: A a1; // no specializations match, uses primary template cout << "A a1 "; a1.describe(); A a2; // uses partial specialization #1 (T=int, I=1) cout << "A a2 "; a2.describe(); A a3; // uses partial specialization #3, (T=char) cout << "A a3 "; a3.describe(); A a4; // uses partial specialization #4, (X=int, T=char, I=1) cout << "A a4 "; a4.describe(); A a5; // error: matches #2 (T=int, T2=int*, I=2) // matches #4 (X=int*, T=int, I=2) // neither one is more specialized than the other The output from the above is: .. raw:: html
     A a1 uses primary template.
     A a2 uses partial template specialization #1 'class A', in which the 2nd parameter is a pointer to 'type of the first parameter'.
     A a3 uses partial template specialization #3 'class A', in which the first parameter is an int, and the 2nd is a pointer and the third is the scalar 5
     A a4 uses partial template specialization #4 'class A', in which The second parameter is a pointer.
     
For ``a1`` no specializations exist that match the template parameters, so the primary template is used. In the case of ``a2``, where the second parameter is ``int *`` and the first parameter is ``int``, partial specialization #1 is more specialized than the primary template. To say "A is more specialized than B" means "A accepts a subset of the types that B accepts". In the case of ``a3``, the third parameter of ``5`` and the second parameter of pointer type, make #3 the only template partial specialization that matches. For ``a5`` above, no most-specialized template can be found since ``a5`` matches #2 and #4 equally. Example of Partial Template Specializaition of std::vector ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Another, real-world example of partial template specialization comes from the GNU implementation of the C++ standard library container ``std::vector``. GNU g++ defines the primary ``std::vector`` template container like: .. code-block:: cpp template > class vector : protected _Vector_base<_Tp, _Alloc> { //... }; and it declares a partial specialization of ``vector`` for ``bool`` like this: .. code-block:: cpp template class vector : protected _Bvector_base<_Alloc> { //... }; Explicit or Full Template Specialization ---------------------------------------- A class template or a function template can be completely specialized for a particular type(s). In this case, the entire class or functoin has a custom reimplementation. The explict or full template specialization explanation examples below are from the IBM Knowledge Center article explaining template `Explicit specialization `_. Definition and declaration of explicit specializations ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ``template<>`` must be preceed a full template specialization, as the example of ``template<> class Sample`` below illustrates. .. note:: Note: However ``template<>`` does not preceeded the definiton of **std::ostream& Sample::print(std::ostream& ostr) const**. Instead the syntax is: **template std::ostream& Sample::print(std::ostream& ostr)**. .. code-block:: cpp template class Sample { T t; public: Sample() {} std::ostream& print(std::ostream&) const; }; // full template specialization for Sample. There is an entirely separate implementation of Sample. template<> class Sample { int i1; int i2; public: Sample() : i1{10}, i2{20} {} std::ostream& print(std::ostream&) const; }; template std::ostream& Sample::print(std::ostream& ostr) const { return ostr << "Primary Sample template. t = " << t << std::endl; } // Note: template<> does not preceed member definition std::ostream& Sample::print(std::ostream& ostr) const { return ostr << "Sample. i1 = = " << i1 << " and i2 = " << i2 << std::endl; } using namespace std; int main(int argc, char** argv) { Sample s1; s1.print(cout); Sample s2; s2.print(cout); return 0; } Definition and declaration of explicit specializations ++++++++++++++++++++++++++++++++++++++++++++++++++++++ The definition of an explicitly specialized class is unrelated to the definition of the primary template. You do not have to define the primary template in order to define the specialization (nor do you have to define the specialization in order to define the primary template). In this example: .. code-block:: cpp template class A; // Primary templae template<> class A; // Explicit specialization for A template<> class A { /* ... */ }; the primary template A above is not defined, but the explicit specialization for type **int** is. You can also use the name of an explicit specialization that has been declared but not defined in the same way as an incompletely defined class. The following example demonstrates this: .. code-block:: cpp template class X { }; template<> class X; // Declared but not defined X* p; X i; // X j; Error: X not defined The compiler does not allow the declaration ``X j`` because the explicit specialization ``X`` is not defined(only declared). You define members of an explicitly specialized template class as you would normal classes, without the ``template<>`` prefix. In addition, you can define the members of an explicit specialization inline; no special template syntax is used in this case. The following example demonstrates a class template specialization: .. code-block:: cpp template class A { public: void f(T); }; template<> class A { public: int g(int); }; int A::g(int arg) { return 0; } int main() { A a; a.g(1234); } .. note:: Explicit specialization ``A`` contains member function ``g()``, which is **not in the primary template**. So full template specializations can exclude functions found in the primary template, and they can include extra methods not found in the primary template. Explicit specialization of function templates +++++++++++++++++++++++++++++++++++++++++++++ In a function template specialization, a template argument is optional if the compiler can deduce it from the type of the function arguments. The following example demonstrates this: .. code-block:: cpp template class X { }; template void f(X); template<> void f(X); The explicit specialization ``template<> void f(X)`` is equivalent to ``template<> void f(X)``. You cannot specify default function arguments in a declaration or a definition for any of the following cases: Explicit specialization of a function template Explicit specialization of a member function template As an example the compiler will not allow the following code: .. code-block:: cpp template void f(T a) { }; template<> void f(int a = 5) { }; // error: default argument(s) not permitted in function template specialization template class X { void f(T a) { } }; template<> void X::f(int a = 10) { };// error: default argument(s) not allowed in member function of full // template specialization Explicit specialization of members of class templates ----------------------------------------------------- Each instantiated class template specialization has its own copy of any static members. You may explicitly specialize static members. The following example demonstrates this: .. code-block:: cpp template class X { public: static T v; static void f(T); }; // primary template static member definitions template T X::v = 0; template void X::f(T arg) { v = arg; } // Specializaions of X::v and X::f(float arg) require // separate definitions of the static member template<> std::string X::v{"Hello"}; template<> void X::f(float arg) { v = arg * 2; } int main() { X x; cout << "x, which is X, has X::v = " << X::v << '\n'; X a, b; cout << "a and b are X, and X::v = " << X::v << '\n'; X c; cout << "c is X, and X::v = " << X::v << '\n'; c.f(10); cout << "After c.f(10), X::v = " << X::v << '\n'; } yields this output: :: x, which is X, has X::v = 0 a and b are X, and X::v = Hello c is X, and X::v = 0 After c.f(10), X::v = 20 Explicit Specialization of Nested Templates +++++++++++++++++++++++++++++++++++++++++++ If you explicitly specialize a template nested within several enclosing class templates, you must prefix the declaration with ``template<>`` for every enclosing class template you specialize. You may leave some enclosing class templates unspecialized; however, you cannot explicitly specialize a class template unless its enclosing class templates are also explicitly specialized. The following example demonstrates explicit specialization of nested member templates: .. code-block:: cpp #include #include using namespace std; template class X { public: template class Y { public: template void f(U,V); void g(U); }; }; template template template void X::Y::f(U, V) { cout << "Primary method definition:\n\n\t'template template template void X::Y::f(U, V) {//...}' \n\n"; } template template void X::Y::g(U) { cout << "Primary method definition:\n\n\t'template template void X::Y::g(U)'\n\n"; } template<> template<> void X::Y::g(int) { cout << "Explicit specialization of void X::Y::g(U):\n\n\t'template<> void X::Y::g(int)'\n\n"; } template<> template<> template void X::Y::f(int, V) { cout << "Explicit specialization of void X::Y::f(U, V):\n\n\t'template<> template void X::Y::f(int, V)'\n\n"; } template<> template<> template<> void X::Y::f(int, int) { cout << "Explicit specialization of void X::Y::f(U, V):\n\n\t'template<> template<> template<> void X::Y::f(int, int)'\n\n"; } // template<> template template // void X::Y::f(U, V) { cout << "Template 6" << "\n\n"; } // template template<> // void X::Y::g(float) { cout << "Template 7" << "\n\n"; } int main() { X::Y a; X::Y b; a.f(1, 2); a.f(3, 'x'); a.g(3); b.f('x', 'y'); b.g('z'); return 0; } See the output of the above program: :: Explicit specialization of void X::Y::f(U, V): 'template<> template<> template<> void X::Y::f(int, int)' Explicit specialization of void X::Y::f(U, V): 'template<> template void X::Y::f(int, V)' Explicit specialization of void X::Y::g(U): 'template<> void X::Y::g(int)' Primary method definition: 'template template template void X::Y::f(U, V) {//...}' Primary method definition: 'template template void X::Y::g(U)' .. todo:: correct text below adding 'Template #'. The compiler would not allow the template specialization definition that would output "Template 6" because it is attempting to specialize a member (function f()) without specialization of its containing class (Y). The compiler would not allow the template specialization definition that would output "Template 7" because the enclosing class of class Y (which is class X) is not explicitly specialized. A friend declaration cannot declare an explicit specialization Partial Template Specialization and Variadic Class Templates ------------------------------------------------------------ A variadic template can take an arbitrary number of template arguments. Variadic class templates often use partial template specializations. Example of variadic templates can be found within the code blocks where :ref:`variadic-class-templates` are described and discussed. Articles on Template specialization and partial specialization -------------------------------------------------------------- * `Partial Template Specialization `_ * `Template Specialization' `_ * Excellent IBM Knowledge Base articles on `Template Specialization `_