Lección 10 · 10 de 20
Plantillas de clases · C++
Cree un búfer circular genérico con una plantilla de clase de C++, con el tipo y el tamaño como parámetros: lecturas de un sensor y archivos recientes.

Una plantilla de clase hace con las clases lo mismo que la plantilla de función con las funciones: RingBuffer<T, N> es un molde y RingBuffer<double, 4> es una clase concreta. Así están hechos std::vector<T> o std::map<K, V>.
El segundo parámetro, std::size_t N, no es un tipo sino un valor fijado al compilar. Por eso puede servir de tamaño de std::array<T, N>, un array de tamaño fijo que vive dentro del objeto, sin memoria dinámica. Las llaves de data_{} lo inicializan con ceros (o con cadenas vacías).
Es un búfer circular: push escribe en la posición next_ y avanza con % N, que vuelve a 0 al llegar al final. Cuando está lleno, cada valor nuevo pisa al más antiguo, así que de las seis temperaturas quedan las cuatro últimas. Es útil para guardar las últimas lecturas de un sensor o un historial de archivos abiertos.
operator[] traduce la posición lógica (0 es la más antigua) a la real dentro del array, y show lo usa con (*this)[i]. El mismo código vale para cualquier T que se pueda escribir con <<: double en temps y std::string en recent. Con un solo archivo, recent muestra [1/3]; con cuatro, se queda con los tres últimos.
Código · main.cpp
#include <array>#include <iostream>#include <string>// A class template: T is the element type, N a size fixed at compile time.template <typename T, std::size_t N>class RingBuffer { std::array<T, N> data_{}; std::size_t next_ = 0, count_ = 0;public: void push(const T& value) { // when full, overwrites the oldest data_[next_] = value; next_ = (next_ + 1) % N; if (count_ < N) ++count_; } std::size_t size() const { return count_; } const T& operator[](std::size_t i) const { return data_[(next_ + N - count_ + i) % N]; } // 0 = oldest void show(const std::string& label) const { std::cout << label << " [" << count_ << "/" << N << "]:"; for (std::size_t i = 0; i < count_; ++i) std::cout << " " << (*this)[i]; std::cout << "\n"; }};int main() { RingBuffer<double, 4> temps; // the last 4 sensor readings for (double t : {18.5, 19.0, 21.2, 22.8, 23.1, 20.4}) temps.push(t); temps.show("Temperatures"); RingBuffer<std::string, 3> recent; // the last 3 files opened recent.push("main.cpp"); recent.show("Recent files"); for (auto f : {"shape.h", "README.md", "Makefile"}) recent.push(f); recent.show("Recent files");}Salida · c++ -std=c++17 main.cpp -o main && ./main
Temperatures [4/4]: 21.2 22.8 23.1 20.4 Recent files [1/3]: main.cpp Recent files [3/3]: shape.h README.md Makefile
Para recordar
template <typename T, std::size_t N> class ...define una plantilla de clase.- Al usarla se dan los argumentos:
RingBuffer<double, 4>. - Un parámetro puede ser un valor constante, como un tamaño.
- Cada combinación de argumentos es una clase distinta.
std::array<T, N>es un array de tamaño fijo, sin memoria dinámica.
Ejercicio
Añada un método average() que devuelva la media de los elementos guardados (para tipos numéricos) y úselo para escribir la temperatura media de las cuatro últimas lecturas.