Tricky basics

Dependent name

The keyword typename was introduced into C++ during the standardization to clarify that an identifier inside a template is a type (or not).


template <typename T>
class MyClass
{
	typename T::SubType * ptr;
	//...
};

Without the typename, the name SubType would be considered as a static member. Thus it would be a concrete variable or object. As a result, the expression:


T::SubType * ptr

would be a multiplication.

In general, typename has to be used whenever a name depends on a template type.

There is may apperance of this situation in STL, like:


typename T::const_iterator pos;

Using this

For class templates with base classes, using a name x by itself is not always equivalent to this->x, even though a member x is inherited:


template <typename T>
class Base
{
public:
	void bar();
};

template <typename T>
class Derived : public Base<T>
{
public:
	void foo() { bar(); }	// calls external bar() or error !!
};

To solve this problem, use:


template <typename T>
class Derived : public Base<T>
{
public:
	void foo() { this->bar(); }	// or Base<T>::bar()
};

Member templates

Class members can also be templates. This is possible for both nested classes and member functions.


template<class T>
class auto_ptr
{
private:
    T* ap;    // refers to the actual owned object (if any)
public:
    typedef T element_type;

    // constructor
    explicit auto_ptr (T* ptr = 0) throw() : ap(ptr) { }

    // copy constructors (with implicit conversion)
    // - note: nonconstant parameter
    auto_ptr (auto_ptr& rhs) throw() : ap(rhs.release()) { }

    template<class Y>
    auto_ptr (auto_ptr<Y>& rhs) throw() : ap(rhs.release()) { }

    // assignments (with implicit conversion)
    // - note: nonconstant parameter
    auto_ptr& operator= (auto_ptr& rhs) throw()
    {
        reset(rhs.release());
        return *this;
    }
    template<class Y>
    auto_ptr& operator= (auto_ptr<Y>& rhs) throw()
    {
        reset(rhs.release());
        return *this;
    }
	// ...

You can also define the templated constructor outside of the class template body:


template<class T>
	template<class Y>
    auto_ptr<T>::auto_ptr(auto_ptr<Y>& rhs) throw() 
										: ap(rhs.release()) { }

template<class T>
    template<class Y>
    auto_ptr<T>& auto_ptr<T>::operator=(auto_ptr<Y>& rhs) throw()
    {
        reset(rhs.release());
        return *this;
    }

Template template parameters

It can be usefull to allow a template parameter itself to be a class template.


std::stack< int, std::vector<int> > vstack;

It would be nice to write this in the following simplified form:


std::stack< int, std::vector> vstack;

To provide this, let us define the stack in the following way:


template <typename T,
   template <typename ELEM> class CONT = std::deque>
class stack
{
protected:
	CONT<T> c;
	//...
};	

What is the difference? In the second form, the second template parameter is declared as being a class template. The default value has changed from std::deque<T> to std::deque. This parameter has to be a class template, which is instantiated for the type that is passed as the first template parameter.

Explicit call of default constructor

The fundamental types, like int, double, etc. has no default constructor. To ensure initialization of such values as template parameters, we can use the explicit call of constructor.


template<typename T>
void foo()
{
	T x = T();
	// ...
}

To make sure, that this happens with the subobjects to, you should use the initializer list of the constructor:


template<typename T>
class MyClass
{
public:
	MyClass() : x() {}
private:
	T x;
};

Explicite Template Instantiation

Templates are instantiated in a lazy way: only those fnctions will be generated which are eplicitelly called.

This default rule can be overruled be the explicite instantiation.


template<typename T>
void print(const T& ) { ... }

template<typename T>
class MyClass
{
	// ...
};

template void print<int>(const int &);	// generate print<int>

template MyClass<double>::MyClass();	// generate constructor 

template class MyClass<long>;		// generate the whole class