Explicit specialization (C++ only)
- 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
Explicit specialization declaration syntax
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.
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;
}
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
template<class T> class A;
template<> class A<int>;
template<> class A<int> { /* ... */ };
The primary template is not defined, but the explicit
specialization is.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
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
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.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
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>)
. - Explicit specialization of a function template
- Explicit specialization of a member function template
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
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)
.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 (functionf()
) 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 classY
(which is classX
) is not explicitly specialized.
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).