std::ranges:: to
|
Definido en el encabezado
<ranges>
|
||
|
template
<
class
C,
ranges::
input_range
R,
class
...
Args
>
requires
(
!
ranges::
view
<
C
>
)
|
(1) | (desde C++23) |
|
template
<
template
<
class
...
>
class
C,
ranges::
input_range
R,
class
...
Args
>
|
(2) | (desde C++23) |
|
template
<
class
C,
class
...
Args
>
requires
(
!
ranges::
view
<
C
>
)
|
(3) | (desde C++23) |
|
template
<
template
<
class
...
>
class
C,
class
...
Args
>
constexpr /*cierre adaptador de rango*/ to ( Args && ... args ) ; |
(4) | (desde C++23) |
|
Plantillas auxiliares
|
||
|
template
<
class
Container
>
constexpr
bool
/*contenedor-reservable*/
=
|
(5) | ( solo para exposición* ) |
|
template
<
class
Container,
class
Reference
>
constexpr
bool
/*container-appendable*/
=
|
(6) | ( solo para exposición* ) |
|
template
<
class
Reference,
class
C
>
constexpr auto /*container-appender*/ ( C & c ) ; |
(7) | ( solo para exposición* ) |
|
template
<
class
R,
class
T
>
concept
/*container-compatible-range*/
=
|
(8) | ( solo para exposición* ) |
Las sobrecargas de la función de conversión de rango construyen un nuevo objeto que no es una vista desde un rango fuente como su primer argumento llamando a un constructor que toma un rango, un
std::from_range_t
constructor etiquetado de rango, un constructor que toma un par iterador-centinela, o insertando por el final cada elemento del rango fuente en el objeto construido con los 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
desde el 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
desde 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
desde el par iterador-centinela (
ranges::
begin
(
r
)
como 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 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_category es válido y denota un tipo que satisface std:: 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 la función
std::
forward
<
Args
>
(
args
)
...
con la siguiente llamada equivalente después de la construcción:
|
if
constexpr
(
ranges::
sized_range
<
R
>
&&
/*reservable-container*/
<
C
>
)
|
(hasta C++26) |
|
if
constexpr
(
ranges
::
approximately_sized_range
<
R
>
|
(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
puede reservar almacenamiento con el tamaño inicial de almacenamiento
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 < 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 cual permite construcciones de rango anidadas dentro del rango si
ranges::
input_range
<
ranges::
range_reference_t
<
C
>>
es
true
.
Sea /*input-iterator*/ un tipo de solo exposición que satisface LegacyInputIterator :
|
struct
/*iterador-de-entrada*/
{
|
( solo para exposición* ) | |
Sea /*DEDUCE-EXPR*/ definido como sigue:
- C ( std:: declval < R > ( ) , std:: declval < Args > ( ) ... ) , si esa expresión es válida.
-
De lo contrario,
C
(
std::
from_range
,
std::
declval
<
R
>
(
)
,
std:: declval < Args > ( ) ... ) , si esa expresión es válida. -
De lo contrario,
C
(
std::
declval
<
/*input-iterator*/
>
(
)
,
std:: declval < /*input-iterator*/ > ( ) ,
std:: declval < Args > ( ) ... ) , si esa expresión es válida. - De lo contrario, el programa está mal formado.
( std:: forward < R > ( r ) , std:: forward < Args > ( args ) ... ) .
Reference
puede ser añadido a
Container
mediante 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
.
Contenidos |
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> #ifndef __cpp_lib_format_ranges #include <format> #include <sstream> auto print_aid(const auto& v) { std::ostringstream out; out << '['; for (int n{}; const auto& e : v) out << (n++ ? ", " : "") << e; out << ']'; return out; } template<typename T> struct std::formatter<std::vector<T>, char> { template<class ParseContext> constexpr ParseContext::iterator parse(ParseContext& ctx) { return ctx.begin(); } template<class FmtContext> FmtContext::iterator format(auto const& s, FmtContext& ctx) const { auto out{print_aid(s)}; return std::ranges::copy(std::move(out).str(), ctx.out()).out; } }; template<typename T> struct std::formatter<std::list<T>, char> { template<class ParseContext> constexpr ParseContext::iterator parse(ParseContext& ctx) { return ctx.begin(); } template<class FmtContext> FmtContext::iterator format(auto const& s, FmtContext& ctx) const { auto out{print_aid(s)}; return std::ranges::copy(std::move(out).str(), ctx.out()).out; } }; #endif int main() { auto vec = std::views::iota(1, 5) | std::views::transform([](int v){ return v * 2; }) | std::ranges::a<std::vector>(); static_assert(std::same_as<decltype(vec), std::vector<int>>); std::println("{}", vec); auto list = vec | std::views::take(3) | std::ranges::a<std::list<double>>(); std::println("{}", list); } void ctor_demos() { // 1.a.1) Inicialización directa { char array[]{'a', 'b', '\0', 'c'}; // El tipo de argumento es convertible al tipo de valor resultante: auto str_to = std::ranges::a<std::string>(array); // Equivalente a std::string str(array); // El tipo de resultado no es un rango de entrada: auto re_to = std::ranges::a<std::regex>(array); // Equivalente a std::regex re(array); } // 1.a.2) from_range ctor { auto list = {'a', 'b', '\0', 'c'}; // El tipo de argumento es convertible al tipo de valor resultante: auto str_to = std::ranges::a<std::string>(list); // Equivalente a // std::string str(std::from_range, list); // El tipo de resultado no es un rango de entrada: [[maybe_unused]] auto pair_to = std::ranges::a<std::pair<std::from_range_t, bool>>(true); // Equivalente a std::pair<std::from_range_t, bool> pair(std::from_range, true); } // 1.a.3) constructor de par de iteradores { auto list = {'a', 'b', '\0', 'c'}; // El tipo de argumento es convertible al tipo de valor resultante: auto devector_to = std::ranges::a<boost::container::devector<char>>(list); // Equivalente a boost::container::devector<char> devector(std::ranges::begin(list), std::ranges::end(list)); // El tipo de resultado no es un rango de entrada: std::regex re; auto it_to = std::ranges::a<std::cregex_iterator>(list, re); // Equivalente a std::cregex_iterator it(std::ranges::begin(list), std::ranges::end(list), re); } }
Salida:
[2, 4, 6, 8] [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]