When you instantiate a template with a given set of template arguments the
compiler generates a new definition based on those template arguments.
You can override this behavior of definition generation. You can
instead specify the definition the compiler uses for a given set of template
arguments. This is called explicit specialization.
You can explicitly specialize any of the following:
Syntax - Explicit Specialization Declaration >>-template--<-->--declaration_name--+------------------------------+--declaration_body->< '-<--template_argument_list-->-'
The template<> prefix indicates that the following template declaration takes no template parameters. The declaration_name is the name of a previously declared template. Note that you can forward-declare an explicit specialization so the declaration_body is optional, at least until the specialization is referenced.
The following example demonstrates explicit specialization:
using namespace std; template<class T = float, int i = 5> class A { public: A(); int value; }; template<> class A<> { public: A(); }; template<> class A<double, 10> { public: A(); }; template<class T, int i> A<T, i>::A() : value(i) { cout << "Primary template, " << "non-type argument is " << value << endl; } A<>::A() { cout << "Explicit specialization " << "default arguments" << endl; } A<double, 10>::A() { cout << "Explicit specialization " << "<double, 10>" << endl; } int main() { A<int,6> x; A<> y; A<double, 10> z; }
The following is the output of the above example:
Primary template non-type argument is: 6 Explicit specialization default arguments Explicit specialization <double, 10>
This example declared two explicit specializations for the primary template (the template which is being specialized) class A. Object x uses the constructor of the primary template. Object y uses the explicit specialization A<>::A(). Object z uses the explicit specialization A<double, 10>::A().
Related References
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). For
example, the compiler will allow the following:
template<class T> class A; template<> class A<int>; template<> class A<int> { /* ... */ };
The primary template is not defined, but the explicit specialization is.
You can use the name of an explicit specialization that has been declared but not defined the same way as an incompletely defined class. The following example demonstrates this:
template<class T> class X { }; template<> class X<char>; X<char>* p; X<int> i; // X<char> j;
The compiler does not allow the declaration X<char> j because the explicit specialization of X<char> is not defined.
Related References
A declaration of a primary template must be in scope at the point of
declaration of the explicit specialization. In other words, an
explicit specialization declaration must appear after the declaration of the
primary template. For example, the compiler will not allow the
following:
template<> class A<int>; template<class T> class A;
An explicit specialization is in the same namespace as the definition of the primary template.
Related References
A member of an explicitly specialized class is not implicitly instantiated
from the member declaration of the primary template. You have to
explicitly define members of a class template specialization. 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:
template<class T> class A { public: void f(T); }; template<> class A<int> { public: int g(int); }; int A<int>::g(int arg) { return 0; } int main() { A<int> a; a.g(1234); }
The explicit specialization A<int> contains the member function g(), which the primary template does not.
If you explicitly specialize a template, a member template, or the member of a class template, then you must declare this specialization before that specialization is implicitly instantiated. For example, the compiler will not allow the following code:
template<class T> class A { }; void f() { A<int> x; } template<> class A<int> { }; int main() { f(); }
The compiler will not allow the explicit specialization template<> class A<int> { }; because function f() uses this specialization (in the construction of x) before the specialization.
Related References
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:
template<class T> class X { }; template<class T> void f(X<T>); template<> void f(X<int>);
The explicit specialization template<> void f(X<int>) is equivalent to template<> void f<int>(X<int>).
You cannot specify default function arguments in a declaration or a definition for any of the following:
For example, the compiler will not allow the following code:
template<class T> void f(T a) { }; template<> void f<int>(int a = 5) { }; template<class T> class X { void f(T a) { } }; template<> void X<int>::f(int a = 10) { };
Related References
Each instantiated class template specialization has its own copy of any static
members. You may explicitly specialize static members. The
following example demonstrates this:
template<class T> class X { public: static T v; static void f(T); }; template<class T> T X<T>::v = 0; template<class T> void X<T>::f(T arg) { v = arg; } template<> char* X<char*>::v = "Hello"; template<> void X<float>::f(float arg) { v = arg * 2; } int main() { X<char*> a, b; X<float> c; c.f(10); }
This code explicitly specializes the initialization of static data member X::v to point to the string "Hello" for the template argument char*. The function X::f() is explicitly specialized for the template argument float. The static data member v in objects a and b point to the same string, "Hello". The value of c.v is equal to 20 after the call function call c.f(10).
You can nest member templates within many enclosing class 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:
#include <iostream> using namespace std; template<class T> class X { public: template<class U> class Y { public: template<class V> void f(U,V); void g(U); }; }; template<class T> template<class U> template<class V> void X<T>::Y<U>::f(U, V) { cout << "Template 1" << endl; } template<class T> template<class U> void X<T>::Y<U>::g(U) { cout << "Template 2" << endl; } template<> template<> void X<int>::Y<int>::g(int) { cout << "Template 3" << endl; } template<> template<> template<class V> void X<int>::Y<int>::f(int, V) { cout << "Template 4" << endl; } template<> template<> template<> void X<int>::Y<int>::f<int>(int, int) { cout << "Template 5" << endl; } // template<> template<class U> template<class V> // void X<char>::Y<U>::f(U, V) { cout << "Template 6" << endl; } // template<class T> template<> // void X<T>::Y<float>::g(float) { cout << "Template 7" << endl; } int main() { X<int>::Y<int> a; X<char>::Y<char> b; a.f(1, 2); a.f(3, 'x'); a.g(3); b.f('x', 'y'); b.g('z'); }
The following is the output of the above program:
Template 5 Template 4 Template 3 Template 1 Template 2
A friend declaration cannot declare an explicit specialization.
Related References
(C) Copyright IBM Corporation 1992, 2006. All Rights Reserved.