Compartir a través de


Adaptadores de intervalo

Los adaptadores de intervalo crean una vista (una de las clases View del std::views espacio de nombres) desde un intervalo. Se recomienda usar un adaptador para crear vistas en lugar de crear los tipos de vista directamente. Los adaptadores son la forma prevista de acceder a las vistas. Son más fáciles de usar y, en algunos casos, más eficientes que crear instancias de los tipos de vista directamente.

Una vista es un objeto ligero que hace referencia a elementos de un intervalo. Una vista puede:

  • Consta solo de determinados elementos de un intervalo.
  • Representa una transformación de elementos de un intervalo.
  • Sea el inverso de, o solo los primeros n elementos de, un intervalo.
  • Ser una combinación de las cosas anteriores.

Una vista es barata, O(1), para copiar, asignar y destruir, independientemente del número de elementos implicados. Considere el ejemplo siguiente:

// requires /std:c++20 or later
#include <ranges>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> input =  {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto divisible_by_three = [](const int n) {return n % 3 == 0;};
    auto square = [](const int n) {return n * n;};

    auto x = input | std::views::filter(divisible_by_three)
                   | std::views::transform(square);

    for (int i : x)
    {
        std::cout << i << ' ';
    }
}
0 9 36 81

El primer adaptador de rango, filter, proporciona una vista que contiene los elementos de input que son divisibles por tres. El otro adaptador de rango, transform, toma la vista que contiene los elementos divisibles por tres y proporciona una vista del cuadrado de esos elementos.

Cuando un adaptador de rango genera una vista, no incurre en el costo de transformar todos los elementos del intervalo para generar esa vista. El costo de procesar un elemento de la vista solo se paga cuando se accede a ese elemento.

La creación de una vista es la preparación para realizar el trabajo en el futuro. En el ejemplo anterior, la creación de la vista no da lugar a que se encuentren todos los elementos divisibles por tres o cuartar esos elementos. El trabajo solo se produce cuando se accede a un elemento de la vista.

Los elementos de una vista suelen ser los elementos reales del intervalo que se usan para crear la vista. La vista normalmente no posee los elementos; simplemente hace referencia a ellos, con la excepción de owning_view. Cambiar un elemento cambia ese elemento en el intervalo desde el que se creó la vista. En el ejemplo siguiente se muestra este comportamiento:

#include <algorithm>
#include <iostream>
#include <ranges>

int main()
{
    int input[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto even = [](const int n) { return n % 2 == 0; };
    auto x = input | std::views::filter(even); // create a view of the even elements from input

    for (int &i : x)
    {
        std::cout << i << ' '; // 0 2 4 6 8 10
    }
    std::cout << '\n'; 

    std::ranges::fill(x, 42); // changes the evens from input[] to 42
    for (int &i : input) // demonstrates that the even elements in the range are modified
    {
        std::cout << i << ' '; // // 42 1 42 3 42 5 42 7 42 9 42
    }
}

Los adaptadores de intervalo vienen en muchas formas. Por ejemplo, hay adaptadores de rango que permiten generar una vista mediante:

  • Filtrado de otro intervalo basado en un predicado (filter).
  • Transformar los elementos en un intervalo (transform).
  • Dividir un intervalo (split).

Los adaptadores de rango se pueden encadenar (compuestos). Ahí es donde el poder y la flexibilidad de los rangos son más evidentes. La composición de adaptadores de rango le permite superar un problema principal con los algoritmos anteriores de la Biblioteca de plantillas estándar (STL), lo que es que no son fáciles de encadenar juntos.

Los siguientes adaptadores de rango están disponibles en el std::views espacio de nombres . El std::views espacio de nombres es un alias de conveniencia para std::ranges::views.

Adaptador de rango Descripción
allC++20 Cree una vista que haga referencia a un intervalo y sus elementos.
commonC++20 Cree una vista que tenga los mismos tipos de iterador y centinela de un intervalo que no lo haga.
countedC++20 Cree una vista de los primeros n elementos de un intervalo, empezando por la ubicación especificada.
dropC++20 Cree una vista a partir de otra vista, omitiendo el número especificado de elementos desde el principio.
drop_whileC++20 Cree una vista que contenga los elementos de un intervalo que permanecen después de que se quiten los elementos iniciales que coincidan con la condición especificada.
elementsC++20 Cree una vista del índice seleccionado en cada valor similar a la tupla en un intervalo.
emptyC++20 Cree una vista que no tenga elementos.
filterC++20 Cree una vista que contenga los elementos de un intervalo que coincidan con la condición especificada.
iotaC++20 Cree una vista que contenga una secuencia de valores crecientes.
istreamC++20 Cree una vista sobre los elementos de una secuencia.
joinC++20 Cree una vista que combine todos los elementos de varios intervalos en una sola vista.
keysC++20 Cree una vista del primer índice en cada valor similar a la tupla de una colección.
lazy_splitC++20 Dividir una vista en subrangos en función de un delimitador.
reverseC++20 Cree una vista de los elementos de un intervalo en orden inverso.
singleC++20 Cree una vista que contenga un elemento.
splitC++20 Dividir una vista en subrangos en función de un delimitador.
takeC++20 Cree una vista de los primeros n elementos desde otra vista.
take_whileC++20 Cree una vista que contenga los elementos iniciales de un intervalo que coincida con la condición especificada.
transformC++20 Cree una vista de elementos transformados desde otra vista.
valuesC++20 Cree una vista del segundo índice en cada valor similar a la tupla de una colección.

En la tabla anterior, un adaptador de rango se describe normalmente como tomar un rango y generar una vista. Para ser precisos, los adaptadores de rango tienen un argumento range que acepta uno de los siguientes:

  • El cv-unqualified tipo modela viewy el argumento es rvalue o se puede copiar.
  • Cuando se pasa el argumento como un valor lvalue, debe modelar range y vivir siempre que la vista.
  • Cuando se pasa el argumento como un valor r, como al llamar a owning_view, debe modelar range y movable.

Las funciones del adaptador de intervalo suelen ser objetos de función, que tienen un aspecto similar a las llamadas de función y aplican restricciones en los tipos que se pueden pasar.

Puede pasar adaptadores de intervalo y el resultado de las operaciones de canalización (|) al código que espera objetos de función. En el ejemplo siguiente, la vista que crea el split adaptador de intervalo se pasa al adaptador de transform rango como si fuera por una llamada de función, ya que el transform adaptador de intervalo es un objeto de función.

std::map<int, string> x = {{0, "Hello, world"}, {42, "Goodbye, world"}};
auto y = x | views::values | views::transform(views::split(' '));
// y is a range whose elements are ranges of whitespace-delimited strings from each value in x:
// {{"Hello", "world"}, {"Goodbye", "world"}}

all

Cree una vista de todos los elementos de un intervalo.

template <ranges::viewable_range R>
constexpr ranges::view auto all(R&& rg) const noexcept;

Parámetros

R
Tipo del intervalo subyacente.

rg
Intervalo desde el que se va a crear la vista.

Valor devuelto

  • Si rg ya es una vista, una copia de rg.
  • Si rg es un valor lvalue que no es de vista, que ref_view hace referencia a rg. (La duración de la vista está vinculada a la duración de rg.
  • Si rg es un valor r que no es de vista, como un objeto temporal, o es el resultado de pasar el intervalo a std::move, un owning_view.

Use std::views::all_t<decltype((rg))> para obtener el tipo de la vista devuelta.

Comentarios

Este adaptador de rango es la mejor manera de convertir un rango en una vista. Una razón para crear una vista a partir de un intervalo es pasarla por valor a bajo costo, si pasar el intervalo por valor podría ser costoso.

Obtener una vista de un rango es una alternativa útil para pasar un intervalo pesado por valor porque las vistas son baratas para crear, copiar y destruir. Una posible excepción es owning_view, que es una vista propietaria del intervalo subyacente.

En general, el peor escenario para destruir una vista tiene O(N) complejidad para el número de elementos del intervalo. Incluso si destruye K copias de vista con N elementos, la complejidad total sigue siendo O(N) porque el intervalo subyacente se destruye solo una vez.

Ejemplo: all

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
    auto myRefView = std::views::all(v); // create a ref_view of the vector
    std::cout << myRefView.size() << '\n'; // 10

    auto myOwningView = std::views::all(std::move(v)); // create an owning_view from a moved vector
    std::cout << myRefView.size() << '\n'; // outputs 0 because myOwningView now owns the elements
    std::cout << v.size() << '\n'; // outputs 0 because myOwningView now owns the elements
    std::cout << myOwningView.size(); // 10 
}
10
0
0
10

common

Cree una vista que tenga el mismo tipo de iterador inicial y centinela a partir de un intervalo que podría no ser así.

template <ranges::viewable_range R>
constexpr ranges::view auto common(R&& rg) const noexcept;

Parámetros

R
Tipo del intervalo subyacente.

rg
Intervalo desde el que se va a crear la vista.

Valor devuelto

  • views::all(rg) si rg es un intervalo con el mismo iterador y tipo sentinel.
  • common_view(views::all(rg)) si rg tiene distintos tipos de iterador y centinela.

Comentarios

Cuando una API requiere que el iterador inicial y el sentinel final tengan el mismo tipo y la vista que usa no cumple ese requisito (o no sabe si lo hace), use este adaptador de intervalo para crear un common_view. Garantiza que el tipo del iterador inicial y el tipo del centinela final son los mismos.

Ejemplo: common

// requires /std:c++20 or higher
#include <ranges>
#include <iostream>
#include <numeric>
#include <list>

int main()
{
    std::list<int> lst{1, 2, 3, 4, 5, 6, 7, 8, 9};

    auto firstFive = std::views::take(lst, 5); 
    // firstFive.begin(), firstFive.end() have different types: counted_iterator versus default_sentinel
    // auto r = std::accumulate(firstFive.begin(), firstFive.end(), 0); // Error: accumulate() requires firstFive.begin() and firstFive.end() types to be the same.
    
    auto common = std::views::common(firstFive); // create a common_view that has the same begin/end iterator types
    std::cout << std::accumulate(common.begin(), common.end(), 0); // Now you can call the API because the iterator types are the same. Outputs 15 (1+2+3+4+5) 
}
15

counted

Cree una vista de los primeros count elementos de un intervalo, empezando por la ubicación especificada.

template<class Iterator>
constexpr auto counted(Iterator&& it, iter_difference_t<Iterator> count);

Parámetros

DifferenceType
Tipo del recuento.

Iterator
Tipo del iterador.

count
Número de elementos que se van a incluir en la vista. No puede ser negativo.

  • Si count == 0es , se devuelve un valor vacío span .
  • Si count es mayor que el número de elementos del intervalo, el comportamiento no está definido.

it
Iterador al elemento del intervalo con el que empezar. El elemento al que apunta el iterador se incluye en la vista creada.

Valor devuelto

span Se devuelve un si it es para contiguous_iterator matrices, vectores y otros contenedores que almacenan sus elementos de forma contigua. De lo contrario, se devuelve un subrange .

Comentarios

Los elementos incluidos son [it, count).

Una vez creada la vista, el número de elementos de la vista permanece igual, incluso si el intervalo que se creó a partir de cambios. Sin embargo, si cambia el intervalo subyacente, el acceso a los elementos de la vista podría dar lugar a un comportamiento indefinido.

Ejemplo: counted

// requires /std:c++20 or later
#include <algorithm>
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto pos5 = std::ranges::find(v, 5);
    auto countedView = std::views::counted(pos5, 5);
    for (auto e : countedView) // outputs 5 6 7 8 9
    {
        std::cout << e << ' ';
    }
    std::cout << '\n';

    // You can pass the range directly if it supports input_or_output_iterator, in which case
    // the count starts from the first element
    const char chars[] = { 'H','i',' ','t','h','e','r','e' };
    for (char c : std::views::counted(chars, 2))
    {
        std::cout << c; // outputs Hi
    }
}
5 6 7 8 9
Hi

drop

Cree una vista que excluya los primeros n elementos de un intervalo.

1) template<ranges::viewable_range R>
constexpr ranges::view auto drop(R&& rg, ranges::range_difference_t<R> count);

2) template<class DifferenceType>
constexpr /* range closure object */ drop(DifferenceType&& count);

Parámetros

DifferenceType
Tipo que describe el número de elementos que se van a omitir.

count
Número de elementos que se van a quitar desde la parte frontal de rg. No puede ser negativo.

  • Si count == 0es , se devuelven todos los elementos de rg .
  • Si count es mayor que el número de elementos de rg, se devuelve una vista vacía.

R
Tipo del rango.

rg
Intervalo que se usa para crear la vista.

Valor devuelto

Vista del intervalo subyacente, con el número especificado de elementos quitados del frente.

Si especifica más elementos que quitar de los que existen en el intervalo subyacente, se devuelve .empty_view

La vista devuelta suele ser, pero no siempre, una especialización de drop_view. Es decir:

Comentarios

Una vez creado, el número de elementos de la vista permanece igual incluso si la vista que se creó a partir de cambios. Sin embargo, si cambia la vista subyacente, el acceso a los elementos de la vista devuelta podría dar lugar a un comportamiento indefinido.

drop es lo contrario de take.

El código mostrado anteriormente como "2)" se puede usar con la sintaxis de canalización: collection | drop(5). O bien, se puede usar con la sintaxis de llamada de función: drop(collection, 5) o drop(5)(collection).

Ejemplo: drop

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{1, 2, 3, 4, 5};
    auto newView = std::views::drop(v, 3);
    for (auto e : newView) // 4 5
    {
        std::cout << e << ' ';
    }
    std::cout << '\n';

    auto numbers = std::views::iota(0) | std::views::take(10); // build a view of 10 integers
    auto latterHalf = numbers | std::views::drop(5);
    for (auto i : latterHalf)
    {
        std::cout << i << ' '; // 5 6 7 8 9
    }
}
4 5
5 6 7 8 9

drop_while

Cree una vista que contenga los elementos de un intervalo que permanecen después de que se quiten los elementos iniciales que coincidan con la condición especificada.

1) template<ranges::viewable_range R, class P>
constexpr ranges::view auto drop_while(R&& rg, P&& predicate);

2) template<class P>
constexpr /*range adaptor closure*/ drop_while(P&& predicate);

Parámetros

R
Tipo del rango.

predicate
Condiciones que determinan qué elementos iniciales se van a quitar del intervalo.

rg
Intervalo subyacente desde el que se va a crear la vista.

Valor devuelto

que drop_while_view consta de los elementos que permanecen cuando se quitan los elementos iniciales que coinciden con el predicado.

Comentarios

Detiene la eliminación de elementos desde rg tan pronto como el predicado devuelve false.

drop_while es lo contrario de take_while.

El código mostrado anteriormente como "2)" se puede usar con la sintaxis de canalización: collection | drop_while(predicate). O bien, se puede usar con la sintaxis de llamada de función: drop_while(collection, predicate) o drop_while(predicate)(collection).

Ejemplo: drop_while

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

void print(auto&& v)
{
    for (auto&& x : v)
    {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::vector<int> v{ 0, 1, 2, 3, -4, 5, 6 };
    auto myView = std::views::drop_while(
        v,
        [](int i) {return i >= 0; });
    print(myView); // -4 5 6

    auto myView2 = v | std::views::drop_while(
        [](int i) {return i < 5; });
    print(myView2); // 5 6
}
-4 5 6
5 6

elements

Cree un elements_view, que es una vista del índice seleccionado en cada valor similar a la tupla en un intervalo. Por ejemplo, dado un intervalo de std::tuple<string, int> valores, cree un elements_view de todos los string elementos de cada tupla.

template<ranges::viewable_range R, size_t N>
constexpr ranges::view auto elements<N>(R&& rg);

Parámetros

N
Índice del elemento que se va a seleccionar de cada valor similar a la tupla que se va a incluir en la vista.

R
Tipo del intervalo subyacente.

rg
Intervalo de valores similares a tupla a partir de los que se va a crear la vista.

Valor devuelto

que elements_view consta del índice seleccionado en cada valor similar a la tupla de una colección.

Ejemplo: elements

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <map>
#include <string>

int main()
{
    std::map<std::string, int> cpp_standards
    {
        {"C++98", 1998},
        {"C++03", 2003},
        {"C++11", 2011},
        {"C++14", 2014},
        {"C++17", 2017},
        {"C++20", 2020}
    };

    // Create an elements_view of all the string elements from each tuple
    for (int const year : std::views::elements<1>(cpp_standards))
    {
        std::cout << year << ' '; // 2003 2011 2014 2017 1998 2020
    }
    std::cout << '\n';

    // Another way, using |: create an elements_view of all the int elements from each tuple
    for (auto&& name : cpp_standards | std::views::elements<0>)
    {
        std::cout << name << ' '; // C++03 C++11 C++14 C++17 C++98 c++20
    }
}
2003 2011 2014 2017 1998 2020
C++03 C++11 C++14 C++17 C++98 c++20

empty

Cree un empty_view, que es una vista que no tiene elementos.

template<class T>
inline constexpr empty_view<T> empty{};

Parámetros

T
Tipo de los elementos de la vista. La vista necesita un tipo de elemento, aunque no haya elementos.

Valor devuelto

Una clase empty_view.

Comentarios

Puede empty_view ser útil cuando se llama al código que requiere una vista, pero no es necesario procesar ninguno de sus elementos.

Ejemplo: empty

// requires /std:c++20 or higher
#include <ranges>
#include <iostream>

int main()
{
    auto anEmptyView = std::views::empty<int>;
    bool isNotEmpty = (bool)anEmptyView;
    std::cout << boolalpha << isNotEmpty << "\n"; // false
}
false

filter

Cree una vista que contenga los elementos de un intervalo que coincidan con la condición especificada.

1) template<ranges::viewable_range R, class P>
    requires {filter_view(forward<R>(rg), forward<P>(predicate));}
constexpr ranges::view auto filter(R&& rg, P&& predicate);

2) template<class P>
constexpr /*range adaptor closure*/ filter(P&& predicate);

Parámetros

P
Tipo del predicado.

predicate
Condiciones que determinan qué elementos mantener en el intervalo.

R
Tipo del intervalo subyacente.

rg
Intervalo desde el que se va a crear la vista.

Valor devuelto

que filter_view contiene los elementos de un intervalo que coinciden con el predicado.

Comentarios

Por motivos de eficiencia, cuando use filter y transform junto con una tubería |, haga lo filter primero para que transform solo los elementos que quiera conservar.

El código mostrado anteriormente como "2)" se puede usar con la sintaxis de canalización: collection | filter(predicate). O bien, se puede usar con la sintaxis de llamada de función: filter(collection, predicate) o filter(predicate)(collection).

Ejemplo: filter

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

void print(auto&& v)
{
    for (auto&& x : v)
    {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::vector<int> v{0, 1, 2, 3, -4, 5, 6};
    auto myView = std::views::filter(v, [](int i) {return i < 5; });
    print(myView); // 0 1 2 3 -4

    auto myView2 = v | std::views::filter([](int i) {return i < 5; }); // pipe syntax
    print(myView2); // 0 1 2 3 -4
}
0 1 2 3 -4
0 1 2 3 -4

iota

Cree una vista que contenga una secuencia de valores crecientes. La secuencia se puede enlazar o no.

template<class V>
constexpr ranges::view auto iota(V&& startValue); // create an unbounded sequence of incrementing values

template<class V, class E>
constexpr ranges::view auto iota(V&& startValue, E&& endValue); // create a bounded sequence of incrementing values

Parámetros

E
Tipo del valor final.

S
Tipo del valor inicial.

startValue
Primer valor de la secuencia.

endValue
Este valor es uno más allá del último valor que estará en la secuencia. Por ejemplo, std::views::iota(0, 5) genera una vista que tiene los valores 0,1,2,3,4.

Valor devuelto

de iota_view una secuencia de valores crecientes.

Comentarios

Para una secuencia sin enlazar, el comportamiento no está definido después de alcanzar el valor máximo de su tipo de datos.

Ejemplo: iota

// requires /std:c++20 or later
#include <ranges>
#include <iostream>

void print(auto&& v)
{
    for (auto&& x : v)
    {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    // create an iota view with its range adaptor (preferred)
    print(std::views::iota(0, 5)); // outputs 0 1 2 3 4
    
    // create an iota_view class directly
    std::ranges::iota_view letters{'a', 'f'};
    print(letters); // a b c d e
}
0 1 2 3 4
a b c d e

istream

Cree una vista sobre los elementos de una secuencia.

template <class Val>
views::istream<Val>(str);

Parámetros

str
Objeto de secuencia. Su tipo se deriva de una especialización de std::basic_istream.

Val
Tipo de los elementos que se van a extraer de la secuencia.

Valor devuelto

Un objeto basic_istream_view.

Este adaptador de rango es equivalente a ranges::basic_istream_view<Val, typename U::char_type, typename U::traits_type>(str), donde U es el tipo de str.

Ejemplo: istream

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <sstream>
#include <vector>

int main()
{
    std::istringstream doubles{"1.1 2.2 3.3 4.4 5.5"};
    for (const auto& elem : std::views::istream<double>(doubles))
    {
        std::cout << elem << ' '; // 1.1 2.2 3.3 4.4 5.5
    }
}
1.1 2.2 3.3 4.4 5.5

join

Cree una vista que combine todos los elementos de varios intervalos en una sola vista.

1) template <ranges::viewable_range R>
[[nodiscard]] constexpr ranges::view auto join(R&& rg) const noexcept;

2) inline constexpr /*range adaptor closure*/ join();

Parámetros

R
Tipo del intervalo subyacente.

rg
Intervalo desde el que se va a crear la vista.

Valor devuelto

que join_view contiene los elementos de todos los intervalos del intervalo subyacente.

Ejemplo: join

#include <iostream>
#include <vector>
#include <ranges>
#include <string>

int main()
{
    // a range of two ranges
    std::vector<std::string> rangeOfRanges[2]{{"C++20", "contains:"}, {"ranges", "modules", "concepts & more."}};

    for (const auto& elem : std::views::join(rangeOfRanges))
    {
        std::cout << elem << ' ';
    }
}
C++20 contains: ranges modules concepts & more.

Comentarios

El código mostrado anteriormente como "2)" se puede usar con la sintaxis de canalización: collection | join. O bien, se puede usar con la sintaxis de llamada de función: join(collection).

keys

Cree un keys_view de los primeros índices en cada valor similar a la tupla de una colección. Esto es útil para extraer claves de contenedores asociativos. Por ejemplo, dado un intervalo de std::tuple<string, int>, cree una vista que consta de todos los string elementos de cada tupla.

template <ranges::viewable_range R>
constexpr auto keys(R&& rg);

Parámetros

R
Tipo del intervalo subyacente.

Valor devuelto

que keys_view consta del primer índice en cada valor similar a la tupla del intervalo.

Ejemplo: keys

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <map>
#include <string>
#include <vector>

int main()
{
    // ========== extract keys from a map

    std::map<std::string, int> cpp_standards
    {
        {"C++98", 1998},
        {"C++03", 2003},
        {"C++11", 2011},
        {"C++14", 2014},
        {"C++17", 2017},
        {"C++20", 2020}
    };

    // Extract all of the keys from the map
    for (std::string standards : std::views::keys(cpp_standards))
    {
        std::cout << standards << ' '; // C++03 C++11 C++14 C++17 C++98 C++20
    }
    std::cout << '\n';

    // ========== Extract keys from a pair

    std::vector<std::pair<std::string, int>> windows
    {
        {"Windows 1.0", 1985},
        {"Windows 2.0", 1987},
        {"Windows 3.0", 1990},
        {"Windows 3.1", 1992},
        {"Windows NT 3.1", 1993},
        {"Windows 95", 1995},
        {"Windows NT 4.0", 1996},
        {"Windows 95", 1995},
        {"Windows 98", 1998},
        {"Windows 1.0", 1985},
        {"Windows 2000", 2000}
    };
    
    // Another way to call the range adaptor is by using '|'
    for (std::string version : windows | std::views::keys)
    {
        std::cout << version << ' '; // Windows 1.0 Windows 2.0 Windows 3.0 ...
    }
}
C++03 C++11 C++14 C++17 C++98 C++20
Windows 1.0 Windows 2.0 Windows 3.0 Windows 3.1 Windows NT 3.1 Windows 95 Windows NT 4.0 Windows 95 Windows 98 Windows 1.0 Windows 2000

lazy_split

Dividir un intervalo en subrangos en función de un delimitador. El delimitador puede ser un único elemento o una vista de elementos.

1) template<viewable_range R, class Pattern>
constexpr view auto lazy_split(R&& rg, Pattern&& delimiter);

2) template<class Pattern>
constexpr /*range adaptor closure*/ lazy_split(Pattern&& delimiter);

Parámetros

delimiter
Valor único o una secuencia de valores que especifican dónde dividir el intervalo.

Pattern
Tipo del delimitador.

R
Tipo del intervalo que se va a dividir.

rg
Intervalo que se va a dividir.

Valor devuelto

que lazy_split_view contiene uno o varios subrangos y es el resultado de dividir el intervalo original en delimiter.

Comentarios

El delimitador no forma parte del resultado. Por ejemplo, si divide el intervalo 1,2,3 en el valor 2, obtendrá dos subrangos: 1 y 3.

Un adaptador relacionado es split. Las principales diferencias entre [split_view](split-view-class.md) and lazy_split_view' son:

Ver Puede dividir un const intervalo Iterador de intervalos
split_view no Admite forward_range o superior
lazy_split_view input_range o superior

Prefiere split_view porque es más eficaz, a menos que deba dividir un rango que sea const.

El código mostrado anteriormente como "2)" se puede usar con la sintaxis de canalización: collection | lazy_split(delimiter). O bien, se puede usar con la sintaxis de llamada de función: lazy_split(collection, delimiter) o lazy_split(delimiter)(collection).

Ejemplo: lazy_split

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> rg{1, 2, 3, 1, 2, 3, 4, 5, 6};

    // split on a single element
    for (const auto& sub : rg | std::views::split(3))
    {
        // outputs:
        // 1 2
        // 1 2
        // 4 5 6
        for (const auto& elem : sub)
        {
            std::cout << elem << ' ';
        }
        std::cout << '\n';
    }

    // split on a sequence of elements
    int delimiters[] = {2, 3};
    for (const auto& subrange : std::views::split(rg, delimiters))
    {
        // outputs 1 1 4 5 6
        for (auto& i : subrange)
        {
            std::cout << i << " ";
        }
    }
}
1 2
1 2
4 5 6
1 1 4 5 6

reverse

Cree una vista de los elementos de un intervalo en orden inverso.

1) template<viewable_range R>
constexpr ranges::view auto reverse(R&& rg);

2) inline constexpr /*range adaptor closure*/ reverse();

Parámetros

R
Tipo del intervalo subyacente que se va a invertir.

rg
Intervalo que se va a invertir.

Valor devuelto

Vista que presenta los elementos del intervalo subyacente en orden inverso. La vista devuelta suele ser, pero no siempre, una especialización de reverse_view. Es decir:

  • Si V es una especialización de reverse_view, el resultado es la vista subyacente del argumento. Un doble inverso es una operación sin operación (sin operación).
  • Si V tiene el formulario subrange<reverse_iterator<I>, reverse_iterator<I>>, el resultado es un subrange de los iteradores desencapsulados. Un doble inverso es una operación sin operación.
  • De lo contrario, el resultado es reverse_view.

Comentarios

El código mostrado anteriormente como "2)" se puede usar con la sintaxis de canalización: collection | reverse. O bien, se puede usar con la sintaxis de llamada de función: reverse(collection).

Ejemplo: reverse

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{ 0, 1, 2, 3, -4, 5, 6 };
    auto rv = v | std::views::reverse; // using the pipe syntax  

    for (auto &&e : rv) // outputs 6 5 -4 3 2 1 0
    {
        std::cout << e << ' ';
    }
    std::cout << '\n';

    // using the range adaptor without using the pipe syntax
    auto rv2 = std::views::reverse(v);
    for (auto &&e : rv2) // outputs 6 5 -4 3 2 1 0
    {
        std::cout << e << ' ';
    }
}
6 5 -4 3 2 1 0
6 5 -4 3 2 1 0

single

Cree un single_view, que es una vista que contiene un elemento.

template<class T>
constexpr ranges::view auto single(T&& t);

Parámetros

T
Tipo del elemento en la vista.

t
Valor del elemento que se va a almacenar en la vista.

Valor devuelto

que single_view contiene t.

Comentarios

Esta vista es útil para fines de prueba, para llamar al código que debe proporcionarse con una vista que tenga al menos un elemento en él.

Ejemplo: single

// requires /std:c++20 or higher
#include <ranges>
#include <string>
#include <tuple>
#include <iostream>

int main()
{
    auto sv = std::views::single(7);
    std::cout << sv.front() << " " << *sv.data() << "\n"; // 7 7
    
    auto sv2 = std::views::single(<std::tuple<double, std::string>{6502, "8-bit"});
    std::cout << std::get<0>(sv2[0]) << " " << std::get<1>(sv2[0]) << "\n"; // 6502 8-bit
}
7 7
6502 8-bit

split

Dividir una vista en subrangos en función de un delimitador. El delimitador puede ser un único elemento o una secuencia de elementos.

1) template<viewable_range R, class Pattern>
constexpr view auto split(R&& rg, Pattern&& delimiter);

2) template<class Pattern>
constexpr /*range adaptor closure*/ split(Pattern&& delimiter);

Parámetros

delimiter
Valor único o una secuencia de valores que especifican dónde dividir el intervalo.

Pattern
Tipo del delimitador.

R
Tipo del intervalo subyacente que se va a dividir.

rg
Intervalo que se va a dividir.

Valor devuelto

que split_view contiene uno o varios subrangos.

Comentarios

El delimitador no forma parte del resultado. Por ejemplo, si divide el intervalo 1,2,3 en el valor 2, obtendrá dos subrangos: 1 y 3.

Un adaptador relacionado es lazy_split. Las principales diferencias entre split_view y lazy_split_view son:

Ver Puede dividir un const intervalo Tipo de intervalo
split_view no Admite forward_range o superior
lazy_split_view Admite input_range o superior

Prefiere split_view porque es más eficaz, a menos que deba dividir un rango que sea const.

El código mostrado anteriormente como "2)" se puede usar con la sintaxis de canalización: collection | split(delimiter). O bien, se puede usar con la sintaxis de llamada de función: split(collection, 5) o split(5)(collection).

Ejemplo: split

// requires /std:c++20 or later
#include <ranges>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> rg{ 1, 2, 3, 1, 2, 3, 4, 5, 6 };

    // split on a single element, 3
    for (const auto& sub : rg | std::views::split(3))
    {
        // This prints out:
        // 1,2
        // 4,5,6
        for (const auto& elem : sub)
        {
            std::cout << elem << ' ';
        }
        std::cout << '\n';
    }

    // split on a sequence of elements, 2,3
    int delimiters[] = {2, 3};
    for (const auto& subrange : std::views::split(rg, delimiters))
    {
        // outputs 1 1 4 5 6
        for (auto& i : subrange)
        {
            std::cout << i << " ";
        }
    }
}
1 2
1 2
4 5 6
1 1 4 5 6

take

Cree una vista que contenga el número especificado de elementos tomados desde el principio de un intervalo.

1) template<ranges::viewable_range R>
constexpr ranges::view auto take(R&& rg, ranges::range_difference_type<R> count);

2) template<class DifferenceType>
constexpr /*range adaptor closure*/ take(DifferenceType&& count); 

Parámetros

R
Tipo del intervalo subyacente.

rg
Intervalo desde el que se va a crear la vista.

count
Número de elementos que se van a tomar desde el principio de rg.

Valor devuelto

La vista devuelta suele ser, pero no siempre, una especialización de take_view. Específicamente:

Comentarios

Si especifica más elementos que tomar que existen en rg, se toman todos los elementos.

take es lo contrario de drop.

El código mostrado anteriormente como "2)" se puede usar con la sintaxis de canalización: collection | take(5). O bien, se puede usar con la sintaxis de llamada de función: take(5, collection) o take(5)(collection).

Ejemplo: take

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::string s{ "abcdefg" };
    auto myView = std::views::take(s, 3);
    for (auto c : myView)
    {
        std::cout << c << ' '; // a b c
    }

    std::cout << std::endl;

    for (auto c : s | std::views::take(3)) // pipe syntax
    {
        std::cout << c << ' '; // a b c
    }
}
a b c
a b c

take_while

Cree una vista que contenga los elementos iniciales de un intervalo que coincida con la condición especificada.

1) template<ranges::viewable_range R, class P>
constexpr ranges::view auto take_while(R&& rg, P&& predicate);

2) template<class P>
constexpr /*range adaptor closure*/ take_while(P&& predicate);

Parámetros

P
Tipo del predicado.

predicate
Condiciones que determinan qué elementos iniciales se van a copiar desde el intervalo.

R
Tipo del intervalo subyacente.

rg
Intervalo desde el que se va a crear la vista.

Valor devuelto

que take_while_view consta de los primeros count elementos que cumplen los criterios especificados en el intervalo.

Comentarios

Deja de tomar elementos de después de rg que el predicado devuelva false o el intervalo se quede sin elementos.

take_while es lo contrario de drop_while.

El código mostrado anteriormente como "2)" se puede usar con la sintaxis de canalización: collection | take_while(pred). O bien, se puede usar con la sintaxis de llamada de función: take_while(collection, pred) o take_while(pred)(collection).

Ejemplo: take_while

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

void print(auto&& v)
{
    for (auto&& x : v)
    {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::vector<int> v{ 0, 1, 2, 3, -4, 5, 6 };
    auto myView = std::views::take_while(
        v, [](int i) {return i >= 0; });
    print(myView); // 0 1 2 3

    print(v | std::views::take_while( // 0 1 2 3 -4
        [](int i) {return i < 5; })); // pipe syntax
}
0 1 2 3
0 1 2 3 -4

transform

Cree una vista de elementos, cada uno de los cuales es una transformación de un elemento en el intervalo especificado.

1) template<viewable_range R, class F>
constexpr ranges::view auto transform(R&& rg, F&& fun);

2) template<class F>
constexpr /*range adaptor closure*/ transform(F&& fun);

Parámetros

F
Tipo del objeto de función que se va a transformar los elementos.

R
Tipo del intervalo subyacente.

fun
Función que transforma los elementos.

rg
Intervalo desde el que se va a crear la vista.

Valor devuelto

que transform_view contiene los elementos transformados de rg.

Comentarios

Por motivos de eficacia, cuando redacte filter y transform, haga lo filter primero para que transform solo los elementos que quiera conservar.

El código mostrado anteriormente como "2)" se puede usar con la sintaxis de canalización: collection | transform(fun). O bien, se puede usar con la sintaxis de llamada de función: transform(collection, fun) o transform(fun)(collection).

Ejemplo: transform

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

void print(auto&& v)
{
    for (auto&& x : v)
    {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::vector<int> v{0, 1, 2, 3, -4, 5, 6};
    auto myView = std::views::transform(v, [](int i) {return i * 2; });
    print(myView); // 0 2 4 6 -8 10 12

    print(v | std::views::transform( // 0 2 4 6 -8 10 12
        [](int i) {return i * 2; })); // pipe syntax
}
0 2 4 6 -8 10 12
0 2 4 6 -8 10 12

values

Cree un values_view objeto que consta del segundo índice en cada valor similar a la tupla de una colección. Esto resulta útil para hacer una vista de los valores de un contenedor asociativo. Por ejemplo, dado un intervalo de std::tuple<string, int> valores, cree una vista que consta de todos los int elementos de cada tupla.

template <range::viewable_range R>
constexpr ranges::view auto values(R&& rg);

Parámetros

R
Tipo del intervalo subyacente.

rg
Intervalo subyacente de valores similares a la tupla.

Valor devuelto

Creado values_view a partir del segundo índice en cada valor similar a la tupla del intervalo.

Ejemplo: values

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <map>
#include <string>
#include <vector>

int main()
{
    // ========== working with a map

    std::map<std::string, int> cpp_standards
    {
        {"C++98", 1998},
        {"C++03", 2003},
        {"C++11", 2011},
        {"C++14", 2014},
        {"C++17", 2017},
        {"C++20", 2020}
    };

    // Extract all of the years from the map
    for (int years : std::views::values(cpp_standards))
    {
        std::cout << years << ' '; // 2003 2011 2014 2017 1998 2020
    }
    std::cout << '\n';

    // ========== working with pairs

    std::vector<std::pair<std::string, int>> windows
    {
        {"Windows 1.0", 1985},
        {"Windows 2.0", 1987},
        {"Windows 3.0", 1990},
        {"Windows 3.1", 1992},
        {"Windows NT 3.1", 1993},
        {"Windows 95", 1995},
        {"Windows NT 4.0", 1996},
        {"Windows 95", 1995},
        {"Windows 98", 1998},
        {"Windows 1.0", 1985},
        {"Windows 2000", 2000}
    };

    // Another way to call the range adaptor by using '|'
    // Create a values_view that contains the year from each pair
    for (int years : windows | std::views::values)
    {
        std::cout << years << ' '; // 1985 1987 1990 1992 ...
    }
}
2003 2011 2014 2017 1998 2020
1985 1987 1990 1992 1993 1995 1996 1995 1998 1985 2000

Alias de tipo de adaptador de intervalo

all_t

Proporciona el tipo de la vista que all devuelve.

template <ranges::viewable_range R>
using all_t = decltype(views::all(std::declval<R>()));

Parámetros

R
Tipo del intervalo subyacente.

Valor devuelto

Tipo de la vista que all devuelve: decltype(views::all(std::declval<R>())).

Ejemplo: all_t

#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
    auto myView = std::views::all(v);
    std::views::all_t<decltype((v))> &viewType = myView;
}

Consulte también

<ranges>
<ranges> Conceptos
Ver clases