Translate

domingo, 6 de septiembre de 2026

Ranges y Views: programación funcional en C++



Cuando pensamos en C++, normalmente pensamos en for, iteradores y algoritmos como std::sort o std::find.

Pero C++ moderno incorporó una forma diferente de trabajar con colecciones: Ranges y Views.


Veamos un ejemplo:

#include <ranges>

#include <vector>

#include <iostream>


int main() {

    std::vector<int> numbers = {1, 2, 3, 4, 5};


    auto result = numbers

        | std::views::filter([](int x) {

            return x % 2 == 0;

        })

        | std::views::transform([](int x) {

            return x * 10;

        });


    for (auto value : result) {

        std::cout << value << " ";

    }

}



Resultado: 20 40


El código se puede leer como un pipeline:

[1, 2, 3, 4, 5]

        ↓

filter(x es par)

        ↓

[2, 4]

        ↓

transform(x * 10)

        ↓

[20, 40]


¿Qué es un Range?

Un Range es una abstracción que representa una secuencia de elementos.


Por ejemplo:

std::vector<int>


puede ser un Range.


También:

std::list<int>

std::array<int, 10>


La idea de Ranges es permitir trabajar con diferentes estructuras utilizando una interfaz común.

En lugar de pensar vector o list podemos pensar en secuencia de elementos


¿Qué es una View?

Una View es una forma de ver o transformar un Range sin necesariamente crear una nueva colección.


Por ejemplo:

auto evenNumbers =

    numbers

    | std::views::filter([](int x) {

        return x % 2 == 0;

    });


Podemos pensar que evenNumbers representa: [2, 4]

Pero no necesariamente se creó un nuevo std::vector.

En cambio, tenemos una vista sobre los datos originales.

Esto nos lleva a una característica muy importante: Lazy evaluation


Las Views normalmente trabajan de forma lazy.

Esto significa que las transformaciones no se ejecutan necesariamente en el momento en que creamos el pipeline.


Por ejemplo:

auto result = numbers

    | std::views::filter(isEven)

    | std::views::transform(multiplyByTen);


En este punto estamos definiendo cómo se van a transformar los datos.

La evaluación ocurre cuando recorremos el resultado:


for (auto value : result) {

    std::cout << value << " ";

}


Esto puede evitar crear colecciones intermedias.

Sin Views podríamos escribir:


std::vector<int> evenNumbers;


for (auto value : numbers) {

    if (value % 2 == 0) {

        evenNumbers.push_back(value);

    }

}


std::vector<int> result;


for (auto value : evenNumbers) {

    result.push_back(value * 10);

}



Con Ranges:


auto result = numbers

    | std::views::filter([](int x) {

        return x % 2 == 0;

    })

    | std::views::transform([](int x) {

        return x * 10;

    });


El código expresa directamente la intención: filtrar → transformar


¿Es programación funcional?

C++ sigue siendo C++.


Pero Ranges y Views incorporan ideas que resultarán familiares para quienes trabajan con programación funcional:

filter

map

pipelines

lazy evaluation


Por ejemplo: std::views::filter(...)

es similar a: filter


Y: std::views::transform(...)

es similar a: map


También podemos combinar operaciones:

numbers

    | std::views::filter(...)

    | std::views::transform(...)

    | std::views::take(10);


El resultado es un pipeline de transformaciones.


Pero con C++20 y C++23, conceptos como pipelines, transformaciones y lazy evaluation forman parte del C++ moderno.


No hay comentarios.:

Publicar un comentario