16.3.3. Constantes en los Templates

Los argumentos de los templates no restrigen su uso a tipos class; se pueden también usar tipos empotrados. Los valores de estos argumentos se convierten en constantes en tiempo de compilación para una 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 que previene de rebasar los límites. La clase Holder es muy parecida a Array excepto que tiene un puntero a Array en vez de un tener incrustrado 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 esta si se están creando un montón de objetos, pero no se está accediendo a todos ellos y se quiere ahorrar almacenamiento.

Hay que resaltar que nunca se almacena internamente el valor de size en la clase, pero se usa como si fuera un dato interno dentro de las funciones miembro.