Click on templates.cpp to get source.
#include <iostream>
#include <typeinfo>

using namespace std;

template <class T>
class A
{public: T x;
 A(T y) : x(y) {}
 typedef T elemT;
};

template class A<int>; // explicit template expansion
                       // is often useful to speed compilation

template <> // template specialization
class A<float>
{public: float z; // new data member
         float x;
A(float y) : z(y+10.0), x(y) {}
};

template< template<class> class C >
// template-template parameters
class B
{public:
 C<int> ci;
 C<float> cf;
 B(int a, float b) : ci(a), cf(b) {}
};

template<class T> // template function: overloaded <<
ostream& operator<<(ostream& out, const A<T>& a)
{out << "An A<" << typeid(T).name() << ">: x member: " << a.x;
 return out; }

template<> // template function: overloaded << specialized for A<float>
ostream& operator<<(ostream& out, const A<float>& a)
{out << "Specialized <<: an A<float>: x member: " << a.x << ", z member: " << a.z;
 return out;
}

#ifdef FWDDCL
class A<double>; // forward declare template specialization
// NOTE: must have template specialization later; is *not* template expansion
// try  g++ -Wall -std=c++23 templates.cpp -DFWDDCL
// to trigger "error: variable ‘A<double> d’ has initializer but incomplete type"
// at variable declaration
#endif

#ifdef DOUBLE
// compile as  g++ -Wall -std=c++23 templates.cpp -DDOUBLE
// or          g++ -Wall -std=c++23 templates.cpp -DDOUBLE -DFWDDCL
template <> // template specialization
class A<double>
{public: double z; // new data member
         double x;
A(double y=0.0) : z(y+10.0), x(y)
{cout << "created an A<double> with z=" << z << endl;}
};
#endif

int main(void)
{A<int> a1(5);
 cout << endl << "A<int> a1(5); cout << a1: " << a1 << endl << endl;

 A<char> a2('A'); // implicit template expansion with char type
 cout << "A<char> a2('A'); cout << a2: " << a2 << endl << endl;

 A<float> a3(1.5f);
 cout << "A<float> a3(1.5f); cout << a3: " << a3 << endl << endl;

 B<A> b(5, 1.5);
 cout <<         "B<A> b(5, 1.5); cout << b.ci: " << b.ci
      << endl << "                cout << b.cf: " << b.cf
      << endl << "                cout << b.cf.z: " << b.cf.z
      << endl << endl;

#ifdef SPECDOUB
 class A<double>; // declaring template specialization
 // triggers compilation error:
 // "specialization of ‘template<class T> class A’ must appear at namespace scope"
 // if template specialization not present
 // try  g++ -Wall -std=c++23 templates.cpp -DSPECDOUB to trigger error
 // compiles with  g++ -Wall -std=c++23 templates.cpp -DDOUBLE -DSPECDOUB
#endif

 A<double> d(3.14159);
 cout << "A<double> d(3.14159); cout << d: " << d << endl << endl;

}//main