tl-ranges - Instalación bajo mingw-w64

La biblioteca tl-ranges de Sy Brand [1], distribuida bajo una licencia de dominio público, proporciona una excelente implementación de adaptadores de rangos que no llegaron a ser incluidos en C++20. Entre ellos destacaríamos (los elementos estandarizados en C++23 se indican con un asterisco):

C++23 - Generador síncrono std::generator

El futuro estándar del lenguaje C++23 incorporará la plantilla de clase std::generator (cabecera <generator>) como modo de obtener generadores síncronos basados en corrutinas que modelen el concepto std::ranges::input_range (recordemos que los algoritmos que operan con este tipo de rangos no deben intentar atravesar un mismo iterador input_range más de una vez). Dichos generadores constituyen vistas que sólo pueden moverse (move-only views), con iteradores de igual naturaleza [1].

Como primer ejemplo, consideremos el siguiente generador de números enteros pertenecientes a la sucesión de Fibonacci, es decir, aquélla que comienza con los números 0 y 1 y para la que cada valor subsiguiente se calcula como suma de los dos elementos que lo preceden. Por sencillez, ignoraremos el inevitable desbordamiento de enteros para valores elevados de la sucesión [1]:

   auto fibonacci_gen() -> std::generator<int>    {       auto a = 0,            b = 1;       while (true) {          co_yield std::exchange(a, std::exchange(b, a + b));       }    }

"Hello, world!" en C++23

C++ ha conocido dos estándares en su etapa moderna que, por su alcance y extensión, han revolucionado la manera de programar en el lenguaje. Nos referimos, por supuesto, a C++11 y C++20. El próximo estándar del lenguaje, C++23, puede considerarse una actualización relativamente menor de C++20, de forma análoga a como C++14 y C++17 constituyeron extensiones naturales de C++11. Aun cuando la pandemia por COVID-19 de los últimos años haya afectado al proceso de trabajo habitual del comité ISO WG21, C++23 logrará publicarse en plazo presentando numerosas novedades, entre las que cabe señalar:

  • A nivel del núcleo del lenguaje: if consteval [1], deducción de this [2], atributos en expresiones lambda [3], atributo [[assume]] [4], auto(x) y auto{x} [5], directiva #warning [6].
  • A nivel de la biblioteca estándar: nuevas vistas std::views [7], <expected> [8], operaciones monádicas para std::optional [9], vistas para arrays multidimensionales <mdspan> [10], adaptadores de contenedores asociativos <flat_map> y <flat_set> [11, 12], generadores síncronos std::generator como soporte para corrutinas [13], funciones de impresión std::print y std::println en <print> [14].

Mónadas para programadores en C++: std::optional (Parte I)

Conceptos matemáticos relevantes: Categorías, functores y mónadas

Desde un punto de vista matemático, una categoría C está constituida por [1]:
  1. Una colección Ob(C) de objetos.
  2. Una colección Hom(C) de flechas o morfismos que enlazan dichos objetos. Un morfismo f del objeto X al objeto Y se denota f: X → Y. El conjunto de morfismos entre los objetos X e Y se denota HomC(X, Y).
  3. Una operación binaria de composición de morfismos. La composición de f: X → Y con g: Y → Z se denota g ∘ f: X → Z
Asumimos los siguientes axiomas en relación a la composición:
  • Asociatividad: Si f: A → Bg: B → C h: C → D, entonces h ∘ (g ∘ f) = (h ∘ g) ∘ f.
  • Para cada objeto X, existe un morfismo identidad idXX → X que se comporta como elemento neutro bajo composición, i.e., para todo morfismo f: X → Y se cumple f ∘ idX idY  f = f. Se puede demostrar que idX es único para cada X.

C++23 - Vista chunk_by

Introducción

El futuro estándar del lenguaje C++23, actualmente en estado feature freeze, proporciona nuevas y útiles vistas para su biblioteca de rangos, entre ellas [1]:

  • std::views::adjacentstd::views::adjacent_transform
  • std::views::cartesian_product
  • std::views::chunkstd::views::chunk_by
  • std::views::join_with
  • std::views::repeat
  • std::views::slide
  • std::views::stride
  • std::views::zip, std::views::zip_transform

La vista std::views::chunk_by, centro de atención de este post, agrupa elementos contiguos de un rango a través de un predicado binario.  Así, dado un rango de partida R=[T] de elementos de tipo T y un predicado binario P, la vista devolverá un rango de rangos [[T]] donde cada subrango contiene elementos contiguos de R que cumplen la siguiente condición: para cada elemento ei en el subrango a excepción del primero, la evaluación del predicado para el elemento inmediatamente anterior ei-1 y ei es verdadera, i.e., P(ei-1,ei)=true [2, 3]. Es importante señalar que no se requiere que dicho predicado constituya una relación de equivalencia.

mdspan: Vistas de arrays multidimensionales

La propuesta de estandarización P0009 para C++23 [1], cuya implementación puede encontrarse en la referencia [2], permite la adecuada gestión en C++ moderno de vistas no-propietarias y potencialmente mutables de arrays multidimensionales. Estas vistas son una herramienta de enorme interés en campos tan diversos como la Física, la Matemática o la Ingeniería y constituyen la piedra angular en torno a la cual el comité ISO C++ pretende diseñar una biblioteca de álgebra lineal basada en BLAS [3].

Sea I un espacio de índices multidimensionales de rango R, definido como el producto cartesiano de intervalos semiabiertos [0, N0⨯ [0, N1⨯ ... ⨯ [0, NR-1), con Nk natural para cada k = 0, ..., R-1. Una vista no propietaria de un array multidimensional de extensión k-ésima igual a Nk asociará a cada R-tupla de índices de acceso i ∈ I una referencia a un elemento accesible a través de un rango contiguo de índices enteros.