std::ranges::to
| Definido en el encabezado <ranges>
|
||
template< class C, ranges::input_range R, class... Args >
requires (!ranges::view<C>)
constexpr C to( R&& r, Args&&... args );
|
(1) | (desde C++23) |
template< template< class... > class C,
ranges::input_range R, class... Args >
constexpr auto to( R&& r, Args&&... args );
|
(2) | (desde C++23) |
template< class C, class... Args >
requires (!ranges::view<C>)
constexpr /*range adaptor closure*/ to( Args&&... args );
|
(3) | (desde C++23) |
template< template< class... > class C, class... Args >
constexpr /*range adaptor closure*/ to( Args&&... args );
|
(4) | (desde C++23) |
| Plantillas auxiliares |
||
template< class Container >
constexpr bool /*reservable-container*/ =
ranges::sized_range<Container> &&
requires (Container& c, ranges::range_size_t<Container> n)
{
c.reserve(n);
{ c.capacity() } -> std::same_as<decltype(n)>;
{ c.max_size() } -> std::same_as<decltype(n)>;
};
|
(5) | (solo exposición*) |
template< class Container, class Reference >
constexpr bool /*container-appendable*/ =
requires (Container& c, Reference&& ref)
{
requires
(
requires { c.emplace_back(std::forward<Reference>(ref)); } ||
requires { c.push_back(std::forward<Reference>(ref)); } ||
requires { c.emplace(c.end(), std::forward<Reference>(ref)); } ||
requires { c.insert(c.end(), std::forward<Reference>(ref)); }
);
};
|
(6) | (solo exposición*) |
template< class Reference, class C >
constexpr auto /*container-appender*/( C& c );
|
(7) | (solo exposición*) |
template< class R, class T >
concept /*container-compatible-range*/ =
ranges::input_range<R> &&
std::convertible_to<ranges::range_reference_t<R>, T>;
|
(8) | (solo exposición*) |
Las sobrecargas de la función de conversión de rango construyen un nuevo objeto que no es una vista a partir de un rango fuente como su primer argumento llamando a un constructor que toma un rango, un std::from_range_t constructor de rango etiquetado, un constructor que toma un par iterador-centinela, o insertando al final cada elemento del rango fuente en el objeto construido con argumentos.
C a partir de los elementos de r de la siguiente manera:C no satisface input_range o std::convertible_to<ranges::range_reference_t<R>, ranges::range_value_t<C>> es true:C a partir del rango fuente std::forward<R>(r) y el resto de los argumentos funcionales std::forward<Args>(args)... si std::constructible_from<C, R, Args...> es true.C a partir de la etiqueta de desambiguación adicional std::from_range, el rango fuente std::forward<R>(r) y el resto de los argumentos funcionales std::forward<Args>(args)... si std::constructible_from<C, std::from_range_t, R, Args...> es true.C a partir del par iterador-centinela (ranges::begin(r) como un iterador y ranges::end(r) como centinela, donde el iterador y el centinela tienen el mismo tipo. En otras palabras, el rango fuente debe ser un rango común), y el resto de los argumentos de función std::forward<Args>(args)... si todas las condiciones siguientes son true:
ranges::common_range<R>- Si
std::iterator_traits<ranges::iterator_t<R>>::iterator_categoryes válido y denota un tipo que satisfacestd::derived_from<std::input_iterator_tag> std::constructible_from<C, ranges::iterator_t<R>, ranges::sentinel_t<R>, Args...>
C a partir del resto de los argumentos de función std::forward<Args>(args)... con la siguiente llamada equivalente después de la construcción:
|
|
(hasta C++26) |
|
|
(desde C++26) |
Si
R satisface sized_range(hasta C++26)approximately_sized_range(desde C++26) y C satisface reservable-container, el objeto construido c de tipo C es capaz de reservar almacenamiento con el tamaño de almacenamiento inicial ranges::size(r)(hasta C++26)ranges::reserve_hint(r)(desde C++26) para evitar asignaciones adicionales durante la inserción de nuevos elementos. Cada elemento de r se añade a c.
Las operaciones anteriores son válidas si ambas condiciones siguientes son true:
std::constructible_from<C, Args...>container-appendable<C, ranges::range_reference_t<R>>
to<C>(ranges::ref_view(r) | views::transform([](auto&& elem)
{
return to<ranges::range_value_t<C>>(std::forward<decltype(elem)>(elem));
}), std::forward<Args>(args)...)
Lo que permite construcciones de rango anidadas dentro del rango si ranges::input_range<ranges::range_reference_t<C>> es true.
r.
Sea /*input-iterator*/ un tipo de solo exposición que satisface LegacyInputIterator:
struct /*input-iterator*/
{
using iterator_category = std::input_iterator_tag;
using value_type = ranges::range_value_t<R>;
using difference_type = std::ptrdiff_t;
using pointer = std::add_pointer_t<ranges::range_reference_t<R>>;
using reference = ranges::range_reference_t<R>;
reference operator*() const; // not defined
pointer operator->() const; // not defined
/*input-iterator*/& operator++(); // not defined
/*input-iterator*/ operator++(int); // not defined
bool operator==(const /*input-iterator*/&) const; // not defined
};
|
(solo exposición*) | |
Sea /*DEDUCE-EXPR*/ definido como sigue:
C(std::declval<R>(), std::declval<Args>()...), si esa expresión es válida.- En caso contrario,
C(std::from_range, std::declval<R>(),std::declval<Args>()...), si esa expresión es válida.
- En caso contrario,
C(std::declval</*input-iterator*/>(),std::declval</*input-iterator*/>(),std::declval<Args>()...), si esa expresión es válida.
- En caso contrario, el programa está mal formado.
La llamada es equivalente a
to<decltype(/*DEDUCE-EXPR*/)> (std::forward<R>(r), std::forward<Args>(args)...).true si satisface ranges::sized_range y es elegible para ser reservable.true si un elemento de tipo Reference puede ser añadido a Container a través de una llamada a función miembro emplace_back, push_back, emplace o insert.return [&c]<class Reference>(Reference&& ref)
{
if constexpr (requires { c.emplace_back(std::declval<Reference>()); })
c.emplace_back(std::forward<Reference>(ref));
else if constexpr (requires { c.push_back(std::declval<Reference>()); })
c.push_back(std::forward<Reference>(ref));
else if constexpr (requires { c.emplace(c.end(),
std::declval<Reference>()); })
c.emplace(c.end(), std::forward<Reference>(ref));
else
c.insert(c.end(), std::forward<Reference>(ref));
};
R cuyo tipo de referencia de rango debe ser convertible a T.Parámetros
| r | - | un objeto de rango fuente |
| args | - | lista de los argumentos para ( 1,2 ) construir un rango o ( 3,4 ) vincular a los últimos parámetros del objeto de cierre de adaptador de rango |
| Requisitos de tipo | ||
-
C
debe ser un tipo de clase sin calificadores cv
(
1,3
)
|
||
Valor de retorno
ranges::to tipo de retorno
Objetos miembro
El objeto retornado se comporta como si no tuviera objeto objetivo, y un objeto std::tuple tup construido con std:: tuple < std:: decay_t < Args > ... > ( std:: forward < Args > ( args ) ... ) , excepto que el comportamiento de asignación del objeto retornado no está especificado y los nombres son solo para exposición.
Constructores
El tipo de retorno de
ranges::to
(
3,4
)
se comporta como si sus constructores de copia/movimiento realizaran una copia/movimiento miembro a miembro. Es
CopyConstructible
si todos sus objetos miembro (especificados arriba) son
CopyConstructible
, y es
MoveConstructible
en caso contrario.
Función miembro
operator()
Dado un objeto
G
obtenido de una llamada previa a
range
::
to
<
/* see below */
>
(
args...
)
, cuando un glvalue
g
que designa
G
es invocado en una expresión de llamada a función
g
(
r
)
, ocurre una invocación del objeto almacenado, como si fuera mediante
- ranges :: to < /* see below */ > ( r, std :: get < Ns > ( g. tup ) ... ) , donde
-
-
r
es un objeto de rango fuente que debe satisfacer
input_range. - Ns es un paquete de enteros 0 , 1 , ..., ( sizeof... ( Args ) - 1 ) .
- g es un lvalue en la expresión de llamada si es un lvalue en la expresión de llamada, y es un rvalue en caso contrario. Por lo tanto std :: move ( g ) ( r ) puede mover los argumentos vinculados a la llamada, donde g ( r ) copiaría.
-
El argumento de plantilla especificado es
(
3
)
Co ( 4 ) el tipo deducido de una plantilla de claseCque no debe satisfacerview.
-
r
es un objeto de rango fuente que debe satisfacer
El programa está mal formado si g tiene tipo calificado volatile.
Excepciones
Solo lanza si la construcción de un objeto no-vista lanza.
Notas
La inserción de elementos en el contenedor puede implicar copia, lo cual puede ser menos eficiente que mover porque se producen referencias lvalue durante la llamada de indirección. Los usuarios pueden optar por usar views:: as_rvalue para adaptar el rango con el fin de que sus elementos siempre produzcan una referencia rvalue durante la llamada de indirección, lo que implica movimiento.
Los paréntesis son obligatorios cuando se utiliza la sintaxis de tubería.
auto vec = r | std::ranges::to<std::vector>; // Error auto vec = r | std::ranges::to<std::vector>(); // Correcto
| Macro de prueba de características | Valor | Estándar | Característica |
|---|---|---|---|
__cpp_lib_ranges_to_container
|
202202L
|
(C++23) |
std::ranges::to
|
__cpp_lib_ranges_reserve_hint
|
202502L
|
(C++26) |
ranges::approximately_sized_range
,
ranges::reserve_hint
, y
cambios
en
std::ranges::to
|
Ejemplo
Un enlace de vista previa: Compiler Explorer
#include <boost/container/devector.hpp>
#include <concepts>
#include <initializer_list>
#include <list>
#include <print>
#include <ranges>
#include <regex>
#include <string>
#include <vector>
int main()
{
auto vec = std::views::iota(1, 5)
| std::views::transform([](int v){ return v * 2; })
| std::ranges::to<std::vector>();
static_assert(std::same_as<decltype(vec), std::vector<int>>);
std::println("1) {}", vec);
auto list = vec | std::views::take(3) | std::ranges::to<std::list<double>>();
std::println("2) {}", list);
}
void ctor_demos()
{
// 1.a.1) Direct init
{
char array[]{'a', 'b', '\0', 'c'};
// Argument type is convertible to result value type:
auto str_to = std::ranges::to<std::string>(array);
// Equivalent to
std::string str(array);
// Result type is not an input range:
auto re_to = std::ranges::to<std::regex>(array);
// Equivalent to
std::regex re(array);
}
// 1.a.2) from_range ctor
{
auto list = {'a', 'b', '\0', 'c'};
// Argument type is convertible to result value type:
auto str_to = std::ranges::to<std::string>(list);
// Equivalent to
// std::string str(std::from_range, list);
// Result type is not an input range:
[[maybe_unused]]
auto pair_to = std::ranges::to<std::pair<std::from_range_t, bool>>(true);
// Equivalent to
std::pair<std::from_range_t, bool> pair(std::from_range, true);
}
// 1.a.3) iterator pair ctor
{
auto list = {'a', 'b', '\0', 'c'};
// Argument type is convertible to result value type:
auto devector_to = std::ranges::to<boost::container::devector<char>>(list);
// Equivalent to
boost::container::devector<char> devector(std::ranges::begin(list),
std::ranges::end(list));
// Result type is not an input range:
std::regex re;
auto it_to = std::ranges::to<std::cregex_iterator>(list, re);
// Equivalent to
std::cregex_iterator it(std::ranges::begin(list), std::ranges::end(list), re);
}
}
Salida:
1) [2, 4, 6, 8]
2) [2, 4, 6]
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| LWG 3984 | C++23 |
la rama de construcción anidada de
ranges::to
resultaba en
programa mal formado si
R&
no modela
viewable_range
|
se hizo bien formado |
| LWG 4016 | C++23 |
la rama de inserción de contenedor de
ranges::to
involucraba uso de iteradores de inserción
|
reemplazado con adición directa
de elementos al contenedor |
Referencias
- Estándar C++23 (ISO/IEC 14882:2024):
-
- 26.5.7 Conversiones de rango [range.utility.conv]