Templates

Waarom templates ?

Met een template kun je een functie of class maken die werkt voor verschillende typen parameters.

NB: Een template is een compiler-constructie. Tijdens het compileren wordt de template uitgewerkt: op de plaatsen waar in de template het algemene type staat, wordt het uiteindelijke type ingevuld. Het resultaat is een functie of class die werkt alsof deze geschreven was met het uiteindelijke type.

LET OP ! Om die reden moeten ook de member-functies van een template volledig uitgeschreven worden in de header file waarin de template class gedefinieerd wordt. Je kunt een template op zich niet compileren tot object-code zo lang het data-type niet bekend is.

Zelf een template maken

Stel dat we een stack nodig hebben. Dan kunnen we een stack voor variabelen van het type int maken. Voor de grootte van de stack gebruiken we long integers zodat we een flink grote stack kunnen maken.


class stack
{
public:
  stack(unsigned long size);
  void push(int newitem);
  int pop(void);
  unsigned long count();
private:
  int* data;
  unsigned long stacksize;
  unsigned long top;
};

Met deze class kun je ints op een stack pushen en eraf poppen, maar alleen ints en geen andere types. Goede kans dat je later ook zo'n stack wilt voor doubles en je kunt verwachten dat iemand dan ook een stack voor strings wil. We kunnen ook een template voor een stack maken zodat het in één keer voor elk willekeurig type werkt.

Dat gaat als volgt: vervang in het bovenstaande voorbeeld alle ints door een template-type, zoals hieronder tpltype en maak van de class een template-class.


template<class tpltype> class stack
{
public:
  stack(unsigned long size);
  void push(tpltype newitem);
  tpltype pop(void);
  unsigned long count();
private:
  tpltype* data;
  unsigned long stacksize;
  unsigned long top;
};

De member-functies zien er als volgt uit:


template<class tpltype> stack<tpltype>::stack(unsigned long size)
{
  data=new tpltype[size];
  stacksize=size;
  top=0;
} // stack()

template<class tpltype> int stack<tpltype>::push(tpltype newitem)
{
  if(top >= stacksize) return -1;
  data[top]=newitem;
  top ++;
  return 0;
} // push()

template<class tpltype> tpltype stack<tpltype>::pop(void)
{
  if(top > 0) top--;
  return data[top];
} // pop()

template<class tpltype> unsigned long stack<tpltype>::count(void)
{
  return top;
} // count()

Uiteindelijk willen we de template ook gebruiken. Eerst maken we drie variabelen: instack, doublestack en stringstack, respectievelijk een stack van ints, een stack van doubles en een stack van strings.


stack<int> intstack(5);
stack<double> doublestack(7);
stack<string> stringstack(3);

Nu kunnen we memberfuncties van die stacks gebruiken om ze te vullen, te zien hoeveel elementen erin zitten en elementen te poppen:


intstack.push(3);
cout << "intstack bevat " << intstack.count() << " elementen:\n";
while(intstack.count()) cout << intstack.pop() << endl;

doublestack.push(3.5);
cout << "doublestack bevat " << doublestack.count() << " elementen:\n";
while(doublestack.count()) cout << doublestack.pop() << endl;
cout << endl;

Zie ook de voorbeelden.