Nontipi come parametri di template

Continuo la lettura di C++ Templates: The Complete Guide, affrontando il terzo capitolo, che tratta i parametri di template che non sono tipi.

Abbiamo visto nei capitoli precedenti come specificare i tipi che parametrizzano il nostro template, sia esso per funzioni o per classi. Qui vediamo come parametrizzare la nostra template usando non un tipo ma un valore.

Curiosamente, per mostrare l'utilizzo di questa feature relativamente avanzata, si fa ricorso ad un esempio che non coinvolge l'uso di un container STL, cosa che é stata fatta per la prima definizione di una classe template.

In pratica il nostro esempio é l'implementazione di uno stack che si appoggia su un array C-style, dove però la dimensione dell'array viene parametrizzata con un parametro, un intero, deciso dall'utente.

Ecco qui a seguire la definizione della classe:

#include <stdexcept>
#include <iostream>

using namespace std;

template <typename T, int MAXSIZE>
class Stack {
private:
T elements[MAXSIZE];
int numElems; // current number of elements
public:
Stack() : numElems(0) {}
void push(const T&);
void pop();
T top() const;
bool empty() const {
return numElems == 0;
}
bool full() const {
return numElems == MAXSIZE;
}
};

template <typename T, int MAXSIZE>
void Stack<T,MAXSIZE>::push (T const& elem)
{
if (numElems == MAXSIZE) {
throw out_of_range("Stack<>::push(): stack is full");
}
elements[numElems++] = elem;
}

template<typename T, int MAXSIZE>
void Stack<T,MAXSIZE>::pop ()
{
if (numElems <= 0) {
throw out_of_range("Stack<>::pop(): empty stack");
}
--numElems; // decrement number of elements
}

template <typename T, int MAXSIZE>
T Stack<T,MAXSIZE>::top () const
{
if (numElems <= 0) {
throw out_of_range("Stack<>::top(): empty stack");
}
return elements[numElems-1]; // return last element
}

Notiamo che il template ora dipende dal tipo T e dall'intero MAXSIZE, questo viene usato per determinare la dimensione dell'array sottostante e per effettuare controlli sull'accesso ai dati dello stack.

Il codice per verificare il funzionamento della classe é il seguente:

#include <iostream>
using namespace std;
//...

int main() {
try {
Stack<int,20> int20Stack; // stack of up to 20 ints
int20Stack.push(7);
cout << int20Stack.top() << endl;
int20Stack.pop();

Stack<string,40> stringStack; // stack of up to 40 strings
stringStack.push("hello");
cout << stringStack.top() << endl;
stringStack.pop();
stringStack.pop();
}
catch (exception const& ex) {
cerr << "Exception: " << ex.what() << endl;
return EXIT_FAILURE; // exit program with ERROR status
}
}

Notiamo come nell'instanziazione della nostra template specifichiamo come secondo parametro un intero, che sarà la dimensione massima del nostro stack.

Il resto del capitolo é dedicato all'approfondimento del tema, con dettagli sull'uso di valori di default e restrizioni sul tipo di valori che si possono passare.

Nessun commento:

Posta un commento