16.3.3. Constantes en las plantillas

Los argumentos de las plantillas no están restringidos a tipos clase; también se pueden usar tipos predefinidos. Los valores de estos argumentos se convierten en constantes en tiempo de compilación para esa instanciación en particular de la plantilla. Se pueden usar incluso valores por defecto para esos argumentos. El siguiente ejemplo nos permite indicar el tamaño de la clase Array durante la instanciación, pero también proporciona un valor por defecto:

//: C16:Array3.cpp
// Built-in types as template arguments
#include "../require.h"
#include <iostream>
using namespace std;

template<class T, int size = 100>
class Array {
  T array[size];
public:
  T& operator[](int index) {
    require(index >= 0 && index < size,
      "Index out of range");
    return array[index];
  }
  int length() const { return size; }
};

class Number {
  float f;
public:
  Number(float ff = 0.0f) : f(ff) {}
  Number& operator=(const Number& n) {
    f = n.f;
    return *this;
  }
  operator float() const { return f; }
  friend ostream&
    operator<<(ostream& os, const Number& x) {
      return os << x.f;
  }
};

template<class T, int size = 20>
class Holder {
  Array<T, size>* np;
public:
  Holder() : np(0) {}
  T& operator[](int i) {
    require(0 <= i && i < size);
    if(!np) np = new Array<T, size>;
    return np->operator[](i);
  }
  int length() const { return size; }
  ~Holder() { delete np; }
};

int main() {
  Holder<Number> h;
  for(int i = 0; i < 20; i++)
    h[i] = i;
  for(int j = 0; j < 20; j++)
    cout << h[j] << endl;
} ///:~

Listado 16.8. C16/Array3.cpp


Como antes, Array es un array de objetos comprobado que impide indexar fuera de los límites. La clase Holder es muy parecida a Array excepto que tiene un puntero a Array en vez de tener incrustado un objeto del tipo Array. Este puntero no se inicializa en el constructor; la inicialización es retrasada hasta el primer acceso. Esto se conoce como inicialización perezosa; se puede usar una técnica como ésta si se está creando un montón de objetos, pero no se accede a todos ellos y se quiere ahorrar almacenamiento.

Hay que resaltar que en ninguna de las dos plantillas se almacena internamente el valor de size en la clase, pero se usa como si fuera un atributo dentro de las funciones miembro.