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 |
---|---|
all C++20 |
Cree una vista que haga referencia a un intervalo y sus elementos. |
common C++20 |
Cree una vista que tenga los mismos tipos de iterador y centinela de un intervalo que no lo haga. |
counted C++20 |
Cree una vista de los primeros n elementos de un intervalo, empezando por la ubicación especificada. |
drop C++20 |
Cree una vista a partir de otra vista, omitiendo el número especificado de elementos desde el principio. |
drop_while C++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. |
elements C++20 |
Cree una vista del índice seleccionado en cada valor similar a la tupla en un intervalo. |
empty C++20 |
Cree una vista que no tenga elementos. |
filter C++20 |
Cree una vista que contenga los elementos de un intervalo que coincidan con la condición especificada. |
iota C++20 |
Cree una vista que contenga una secuencia de valores crecientes. |
istream C++20 |
Cree una vista sobre los elementos de una secuencia. |
join C++20 |
Cree una vista que combine todos los elementos de varios intervalos en una sola vista. |
keys C++20 |
Cree una vista del primer índice en cada valor similar a la tupla de una colección. |
lazy_split C++20 |
Dividir una vista en subrangos en función de un delimitador. |
reverse C++20 |
Cree una vista de los elementos de un intervalo en orden inverso. |
single C++20 |
Cree una vista que contenga un elemento. |
split C++20 |
Dividir una vista en subrangos en función de un delimitador. |
take C++20 |
Cree una vista de los primeros n elementos desde otra vista. |
take_while C++20 |
Cree una vista que contenga los elementos iniciales de un intervalo que coincida con la condición especificada. |
transform C++20 |
Cree una vista de elementos transformados desde otra vista. |
values C++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 modelaview
y 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 modelarrange
ymovable
.
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 derg
. - Si
rg
es un valor lvalue que no es de vista, queref_view
hace referencia arg
. (La duración de la vista está vinculada a la duración derg
. - Si
rg
es un valor r que no es de vista, como un objeto temporal, o es el resultado de pasar el intervalo astd::move
, unowning_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)
sirg
es un intervalo con el mismo iterador y tipo sentinel.common_view(views::all(rg))
sirg
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 == 0
es , se devuelve un valor vacíospan
. - 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 == 0
es , se devuelven todos los elementos derg
. - Si
count
es mayor que el número de elementos derg
, 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:
- Si
V
es una especialización deempty_view
, o es una especialización despan
,basic_string_view
,iota_view
osubrange
que es ysized_range
random_access_range
, el resultado es una especialización deV
. - De lo contrario, el resultado es
drop_view
.
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 |
sí | 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 dereverse_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 formulariosubrange<reverse_iterator<I>, reverse_iterator<I>>
, el resultado es unsubrange
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 |
sí | 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:
- Si
V
es una especialización deempty_view
, o es una especialización despan
,basic_string_view
,iota_view
osubrange
que es ysized_range
random_access_range
, el resultado es una especialización deV
. - De lo contrario, el resultado es
take_view
.
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;
}