Última actualización:2026-10-12
La biblioteca Ranges de C++20¶
ranges es una de las características principales de C++20, y los "view" son una parte bastante importante de ella. Antes de C++20, los algoritmos de la biblioteca estándar se implementaban sobre iteradores, por ejemplo: std::sort.
Iteradores + algoritmos permiten completar algunas operaciones complejas; por ejemplo, si quiero ordenar en sentido inverso:
Pero esto también acarrea algunos problemas:
- Es fácil mezclar dos iteradores incompatibles.
- La capacidad de composición de los algoritmos es demasiado débil y obliga a almacenar variables intermedias
Por ejemplo: supongamos un sistema de información de estudiantes y que queremos calcular la suma de las GPA de los estudiantes cuya edad está en el intervalo 21-25 y con GPA >= 3.5. Antes de C++17 podríamos escribir un pseudocódigo como este:
std::vector<Student> students
std::vector<Student> selected;
std::copy_if(students.begin(), students.end(), std::back_inserter(selected),
[](const Student& student) {
return student.age >= 21 && student.age <= 25 && student.gpa >= 3.5;
});
double s = std::accumulate(
selected.begin(), selected.end(), 0.0,
[](double sum, const Student& student) { return sum + student.gpa; });
Se ve que, al filtrar la información de los estudiantes que cumplen las condiciones, hay que copiarla a selected y luego sumar.
C++20 introduce una forma de escribirlo más concisa y eficiente: usando rangos y el operador de tubería | para encadenar varias operaciones, se puede sumar directamente sin variables intermedias; por ejemplo:
double s = 0.0;
for (const auto& student :
students | std::views::filter([](const auto& s) {
return s.age >= 21 && s.age <= 25 && s.gpa >= 3.5;
}) | std::views::transform([](const auto& s) { return s.gpa; })) {
s += student;
}
Se ve que varios algoritmos se encadenan sin costuras, reduciendo las asignaciones de memoria de las variables temporales intermedias; la legibilidad también aumenta notablemente, conectando las distintas manipulaciones mediante la tubería |.
A continuación, exploremos juntos los contenidos relacionados con los ranges de C++20.
1.Conceptos básicos¶
1.range
Un range es un concepto abstracto que representa una secuencia. Puede ser cualquier contenedor con iteradores, o un objeto que defina las funciones begin() y end(). std::vector, std::list, etc., son ejemplos de rangos. Los arrays también pueden considerarse rangos.
2.view
Un view es un acceso de solo lectura a un Range. Es una forma de evaluación perezosa: solo calcula cuando se necesita, lo que significa que no almacena datos realmente. Por ejemplo: std::views::filter y std::views::transform son ejemplos típicos de view. Nos permiten filtrar y transformar un range sin crear realmente contenedores nuevos.
3.algorithm
Los algoritmos son funciones que operan sobre un range o un view; por ejemplo, std::sort, std::find, etc., son ejemplos de algoritmos.
4.|
El operador de tubería | permite encadenar vistas y algoritmos, tomando el resultado del lado izquierdo como entrada del lado derecho. Hace el código más claro y conciso. Por ejemplo: students | std::views::filter(...) pasa el rango students a std::views::filter para la operación de filtrado, y luego pasa el resultado a las operaciones siguientes.
Tomando como ejemplo el cálculo con students de arriba: en ese ejemplo usamos el rango students como entrada de la vista filter mediante |, luego el resultado como entrada de la vista transform, y al final obtenemos un rango sobre el que iteramos, sumando mediante un algoritmo de acumulación para obtener el resultado.
double s = 0.0;
for (const auto& student :
students | std::views::filter([](const auto& s) {
return s.age >= 21 && s.age <= 25 && s.gpa >= 3.5;
}) | std::views::transform([](const auto& s) { return s.gpa; })) {
s += student;
}
Como puede verse, usar ranges tiene las ventajas siguientes:
- Mejora la legibilidad del código
- Evaluación perezosa: Ranges introduce el concepto de vista (view), que permite la evaluación perezosa, es decir, calcular el resultado solo cuando se necesita.
Por ejemplo: solo se calcula al hacer *v.begin().
- Menos errores: el diseño de Ranges ayuda a reducir algunos errores habituales en las operaciones tradicionales con iteradores, como usar iteradores incompatibles.
- Etcétera.
El concepto de rango introduce distintos conceptos para describir diferentes tipos de rangos. Estos conceptos ayudan a comprender y restringir mejor las propiedades de los rangos en programación genérica. Estos son algunos conceptos de rango de uso frecuente:
| Concepto | Descripción | Ejemplos de contenedores |
|---|---|---|
std::ranges::input_range |
Se puede iterar al menos una vez de principio a fin | std::forward_list、std::list、std::duque、std::array、std::vector |
std::ranges::forward_range |
Se puede iterar varias veces de principio a fin | std::forward_list、std::list、std::duque、std::array、std::vector |
std::ranges::bidirectional_range |
Los iteradores también pueden desplazarse hacia atrás con -- |
std::list、std::duque、std::array、std::vector |
std::ranges::random_access_range |
Puedes saltar a un elemento [] en tiempo constante |
std::duque、std::array、std::vector |
std::ranges::contiguous_range |
Los elementos siempre se almacenan de forma contigua en memoria | std::array、std::vector |
2.Uso¶
Usar esta característica es bastante sencillo: basta con incluir el archivo de cabecera y usar la interfaz.
Por ejemplo: filtrar los números pares de un conjunto de números.
#include <ranges>
auto evenNumbers = numbers | std::views::filter([](int x) { return x % 2 == 0; });
Compilación: basta con especificar -std.
Sobre el soporte de los compiladores puede consultarse la siguiente lista:
gcc >=10, clang >=13 (parcial), >=15 soporte completo.
Temas relacionados¶
- Introducción a las corrutinas de C++20 | C++那些事
- C++20 channel en la práctica | C++那些事
- Conceptos Concepts de C++20 | C++那些事
- constexpr y la expresión coma en C++20 | C++那些事
- Orden de bytes endian en C++20 | C++那些事
- Expresiones lambda de C++20 (parte 1) | C++那些事
- Módulos Modules de C++20 | C++那些事
- Diseño y trampas de std::span en C++20 | C++那些事
- Guía de las novedades de C++20 | C++那些事
- C++20 [[likely]] y [[unlikely]] | C++那些事