Explicit specialization (C++ only)

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 templates:
  • Function template
  • Class template
  • Member function of a class template
  • Static data member of a class template
  • Member class of a class template
  • Member function template of a class template
  • Member class template of a class template
Read syntax diagramSkip visual syntax diagram
Explicit specialization declaration syntax

>>-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;
}
See 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().

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). See the following example:
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.

Explicit specialization and scope

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 code:
template<> class A<int>;
template<class T> class A;
An explicit specialization is in the same namespace as the definition of the primary template.

Class members of explicit specializations

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.

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:
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 cases:
  • Explicit specialization of a function template
  • Explicit specialization of a member function template
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) { };

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:
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');
}
See the output of the above program:
Template 5
Template 4
Template 3
Template 1
Template 2
  • 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.
C++11 ends

Explicit specialization and inline namespace definitions

Inline namespace definitions are namespace definitions with an initial inline keyword. Members of an inline namespace can be explicitly instantiated or specialized as if they were also members of the enclosing namespace. For more information, see Inline namespace definitions (C++11).

C++11 ends