Member templates
template<typename T>
class Pointer
{
public:
Pointer(T* aPtr)
: myPtr( aPtr ) { }
template<typename Q>
Pointer(const Pointer<Q> aPtr)
: myPtr( aPtr.myPtr ) { }
//...
private:
T* myPtr;
};
In the above example, Pointer has a templatised constructor that
allows a Pointer<X> to be constructed from Pointer<Y>
if and only if an X* can be initialised with a Y*. In other
words the "normal" derived to base pointer conversion can be made to work
for smart pointers:
class Base { ... };
class Derived : public Base { ... };
Pointer<Base> p( new Derived );
// same as:
Pointer<Base> p( Pointer<Derived>( new Derived ) );
// which is well-formed because a Derived* can be
// used to initialise a Base*
Almost any member of a class can be a template: nested classes, functions,
constructors, conversion operators. A destructor cannot be a template
(because there is only one destructor per class).
Defining member templates outside the class can look a little unwieldy but the syntax is "obvious" when you think about it:
class Thing
{
public:
template<typename T>
class Nested
{
public:
template<typename Q>
void f(T t, Q q);
void g(T t);
};
template<typename T>
void h(T t);
};
template<typename T>
template<typename Q>
void Thing::Nested<T>::f(T t, Q q) { ... }
template<typename T>
void Thing::Nested<T>::g(T t) { ... }
template<typename T>
void Thing::h(T t) { ... }
// the constructors for Pointer above,
// defined out of line:
template<typename T>
Pointer<T>::Pointer(T* aPtr) ...
template<typename T>
template<typename Q>
Pointer<T>::Pointer(const Pointer<Q> aPtr) ...
Specialising member templates also needs care but, again, follows an "obvious" pattern:
// definition of f for specialisation of
// Thing::Nested:
template<>
template<typename Q>
void Thing::Nested<int>::f(int t, Q q) { ... }
// specialisation of f for specialisation of
// Thing::Nested:
template<>
template<>
void Thing::Nested<int>::f(int t, char* q) { ... }
// specialisation of f for arbitrary Thing::Nested:
template<typename T>
template<>
void Thing::Nested<T>::f(T t, char* q) { ... }
See also The Casting Vote: Austin - March '95.