template<class T = int> struct A { static int x; }; template<class U> void g(U) { } template<> struct A<double> { }; // specialize for T == double template<> struct A<> { }; // specialize for T == int template<> void g(char) { } // specialize for U == char // U is deduced from the parameter type template<> void g<int>(int) { } // specialize for U == int template<> int A<char>::x = 0; // specialize for T == char template<class T = int> struct B { static int x; }; template<> int B<>::x = 1; // specialize for T == int
template<class T> struct A {
static T t;
};
typedef int function();
A<function> a; // ill-formed: would declare A<function>::t as a static member function
template<class T> class B { /* ... */ }; template<class T> class D : public B<T> { /* ... */ }; void f(void*); void f(B<int>*); void g(D<int>* p, D<char>* pp, D<double>* ppp) { f(p); // instantiation of D<int> required: call f(B<int>*) B<char>* q = pp; // instantiation of D<char> required: convert D<char>* to B<char>* delete ppp; // instantiation of D<double> required }
template<class T, class U> struct Outer { template<class X, class Y> struct Inner; template<class Y> struct Inner<T, Y>; // #1a template<class Y> struct Inner<T, Y> { }; // #1b; OK: valid redeclaration of #1a template<class Y> struct Inner<U, Y> { }; // #2 }; Outer<int, int> outer; // error at #2
template<typename T> struct Friendly {
template<typename U> friend int f(U) { return sizeof(T); }
};
Friendly<char> fc;
Friendly<float> ff; // ill-formed: produces second definition of f(U)
template<class T> struct Z { void f(); void g(); }; void h() { Z<int> a; // instantiation of class Z<int> required Z<char>* p; // instantiation of class Z<char> not required Z<double>* q; // instantiation of class Z<double> not required a.f(); // instantiation of Z<int>::f() required p->g(); // instantiation of class Z<char> required, and // instantiation of Z<char>::g() required }
template <class T> struct S { operator int(); }; void f(int); void f(S<int>&); void f(S<float>); void g(S<int>& sr) { f(sr); // instantiation of S<int> allowed but not required // instantiation of S<float> allowed but not required };
namespace N { template<class T> class List { public: T* get(); }; } template<class K, class V> class Map { public: N::List<V> lt; V get(K); }; void g(Map<const char*,int>& m) { int i = m.get("Nicholas"); }
template<class T> void f(T x, T y = ydef(T()), T z = zdef(T())); class A { }; A zdef(A); void g(A a, A b, A c) { f(a, b, c); // no default argument instantiation f(a, b); // default argument z = zdef(T()) instantiated f(a); // ill-formed; ydef is not declared }
template<class T> class X { X<T>* p; // OK X<T*> a; // implicit generation of X<T> requires // the implicit instantiation of X<T*> which requires // the implicit instantiation of X<T**> which … };
explicit-instantiation: extern template declarationThere are two forms of explicit instantiation: an explicit instantiation definition and an explicit instantiation declaration.
template<class T> class Array { void mf(); }; template class Array<char>; template void Array<int>::mf(); template<class T> void sort(Array<T>& v) { /* ... */ } template void sort(Array<char>&); // argument is deduced here namespace N { template<class T> void f(T&) { } } template void N::f<int>(int&);
namespace N { template<class T> class Y { void mf() { } }; } template class Y<int>; // error: class template Y not visible in the global namespace using N::Y; template class Y<int>; // error: explicit instantiation outside of the namespace of the template template class N::Y<char*>; // OK: explicit instantiation in namespace N template void N::Y<double>::mf(); // OK: explicit instantiation in namespace N
template<class T> class Array { /* ... */ }; template<class T> void sort(Array<T>& v) { /* ... */ } // instantiate sort(Array<int>&) – template-argument deduced template void sort<>(Array<int>&);
explicit-specialization: template < > declaration
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*>&);
template<> class X<int> { /* ... */ }; // error: X not a template template<class T> class X; template<> class X<char*> { /* ... */ }; // OK: X is a template
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
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
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
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>
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>&);
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
template<> X Q<int>::x; // declaration template<> X Q<int>::x (); // error: declares a function template<> X Q<int>::x { }; // definition
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) { }
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();
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