Declaring and Defining Templates

In a header file, declare your class functions and function templates, as shown in Listing 3.9.

Listing 1. templ.h: A Template Declaration File

template <class T>
class Templ {
T member;
public:
Templ(T x) { member=x; }
T Get();
};

template <class T>
T Max(T,T);

In a source file, include the header file, then define the function templates and the member functions of the class templates. Listing 3.10 shows you an example.

This source file is a template definition file, which you include in any file that uses your templates. You do not need to add the template definition file to your project. Although this is technically a source file, you work with it as if it were a header file.

The template definition file does not generate code. The compiler cannot generate code for a template until you specify what values it should substitute for the template arguments. Specifying these values is called instantiating the template. See Instantiating a Template.

Listing 2. templ.cp: A Template Definition File

#include "templ.h"

template <class T>
T Templ<T>::Get()
{
return member;
}

template <class T>
T Max(T x, T y)
{
return ((x>y)?x:y);
}

WARNING! Do not include the original template declaration file, which ends in .h, in your source file. Otherwise, the compiler generates an error saying that the function or class is undefined.

Providing declarations when declaring the template

Carbide.c++ processes any declarations in a template when the template is declared, not when it is instantiated.

Although the C++ compiler currently accepts declarations in templates that are not available when the template is declared, future versions of the compiler will not. Listing 3.11 shows some examples.

Listing 3.11 Declarations in Template Declarations

// You must define names in a class template declaration

struct bar;
template<typename T> struct foo {
bar *member; // OK
};
struct bar { };
foo<int> fi;

// Names in template argument dependent base classes:

template<typename T> struct foo {
typedef T *tptr;
};

template<typename T> struct foo {
typedef T *tptr;
};
template<typename T> struct bar : foo<T> {
typename foo<T>::tptr member; // OK
};

// The correct usage of typename in template argument
// dependent qualified names in some contexts:

template<class T> struct X {
typedef X *xptr;
xptr f();
};
template<class T> X<T>::xptr X<T>::f() // 'typename' missing
{
return 0;
}

// Workaround: Use 'typename':

template<class T> typename X<T>::xptr X<T>::f() // OK
{
return 0;
}